home *** CD-ROM | disk | FTP | other *** search
/ Just Call Me Internet / Just Call Me Internet.iso / prog / atari / c / ck5a189s / ckufio.c < prev    next >
C/C++ Source or Header  |  1993-07-04  |  87KB  |  3,141 lines

  1. #ifdef OS2
  2. char *ckzv = "OS/2 File support, 5A(074) 11 Jun 93";
  3. #else
  4. #ifdef aegis
  5. char *ckzv = "Aegis File support, 5A(074) 11 Jun 93";
  6. #else
  7. char *ckzv = "UNIX File support, 5A(074) 11 Jun 93";
  8. #endif /* aegis */
  9. #endif /* OS2 */
  10.  
  11. /* C K U F I O  --  Kermit file system support for UNIX, OS/2, and Aegis */
  12.  
  13. /*
  14.   Author: Frank da Cruz (fdc@columbia.edu, FDCCU@CUVMA.BITNET),
  15.   Columbia University Academic Information Systems, New York City.
  16.  
  17.   Copyright (C) 1985, 1993, Trustees of Columbia University in the City of New
  18.   York.  The C-Kermit software may not be, in whole or in part, licensed or
  19.   sold for profit as a software product itself, nor may it be included in or
  20.   distributed with commercial products or otherwise distributed by commercial
  21.   concerns to their clients or customers without written permission of the
  22.   Office of Kermit Development and Distribution, Columbia University.  This
  23.   copyright notice must not be removed, altered, or obscured.
  24. */
  25.  
  26. /* Include Files */
  27.  
  28. #include "ckcdeb.h"
  29.  
  30. #include <signal.h>
  31.  
  32. #ifdef MINIX
  33. #include <limits.h>
  34. #endif /* MINIX */
  35. #ifdef POSIX
  36. #include <limits.h>
  37. #endif /* POSIX */
  38.  
  39. /* Directory structure header file */
  40.  
  41. #ifdef OS2
  42. /*
  43.  
  44.   C-Kermit's OS/2 support originally by Chris Adie <C.Adie@uk.ac.edinburgh>
  45.   Edinburgh University Computing Service, Scotland, for C-Kermit 4F.  Adapted
  46.   to C-Kermit 5A and integrated into the UNIX support module by Kai Uwe Rommel
  47.   <rommel@informatik.tu-muenchen.de>, Muenchen, Germany, December 1991.
  48. */
  49.  
  50. /*
  51.   Directory Separator macros, to allow this module to work with both UNIX and
  52.   OS/2: Because of ambiguity with the command line editor escape \ character,
  53.   the directory separator is currently left as / for OS/2 too, because the
  54.   OS/2 kernel also accepts / as directory separator.  But this is subject to
  55.   change in future versions to conform to the normal OS/2 style.
  56. */
  57. #define DIRSEP       '/'
  58. /* #define DIRSEP       '\\' */
  59. #define ISDIRSEP(c)  ((c)=='/'||(c)=='\\')
  60. #else /* not OS2 */
  61. #define DIRSEP       '/'
  62. #define ISDIRSEP(c)  ((c)=='/')
  63. #endif /* OS2 */
  64.  
  65. #ifdef SDIRENT
  66. #define DIRENT
  67. #endif /* SDIRENT */
  68.  
  69. #ifdef XNDIR
  70. #include <sys/ndir.h>
  71. #else /* !XNDIR */
  72. #ifdef NDIR
  73. #include <ndir.h>
  74. #else /* !NDIR, !XNDIR */
  75. #ifdef RTU
  76. #include "/usr/lib/ndir.h"
  77. #else /* !RTU, !NDIR, !XNDIR */
  78. #ifdef DIRENT
  79. #ifdef SDIRENT
  80. #include <sys/dirent.h>
  81. #else
  82. #include <dirent.h>
  83. #endif /* SDIRENT */
  84. #else
  85. #ifdef OS2
  86. #define OPENDIR
  87. #define DIRENT
  88. #include "ckodir.h"
  89. #else/* !RTU, !NDIR, !XNDIR, !DIRENT, !OS2, i.e. all others */
  90. #include <sys/dir.h>
  91. #endif /* OS2 */
  92. #endif /* DIRENT */
  93. #endif /* RTU */
  94. #endif /* NDIR */
  95. #endif /* XNDIR */
  96.  
  97. #ifdef OS2                /* OS/2 file system interface */
  98. #define BSD4                /* is like Berkeley UNIX */
  99. #define NOFILEH                /* with no <file.h> */
  100. #include <sys/utime.h>
  101. #include <stdlib.h>
  102. #include <process.h>
  103. extern int binary;            /* We need to know this for open() */
  104. #ifdef __IBMC__
  105. extern FILE *popen(char *, char *);
  106. extern int pclose(FILE *);
  107. #else
  108. #ifndef __EMX__
  109. #define popen    _popen
  110. #define pclose   _pclose
  111. #include <share.h>
  112. #define fopen(n, m)  _fsopen(n, m, SH_DENYWR)
  113. #endif /* __EMX__ */
  114. #endif /* __IBMC__ */
  115. #else
  116. #include <pwd.h>            /* Password file for shell name */
  117. #endif /* OS2 */
  118.  
  119. #ifndef OS2
  120. #ifdef SYSUTIMEH            /* <sys/utime.h> if requested,  */
  121. #include <sys/utime.h>            /* for extra fields required by */
  122. #endif /* SYSUTIMEH */            /* 88Open spec. */
  123. #endif /* OS2 */
  124.  
  125. #ifdef POSIX
  126. #define TIMESTAMP
  127. #define SYSUTIMEH
  128. #include <utime.h>
  129. #endif /* POSIX */
  130.  
  131. #ifdef BSD44                /* BSD 4.4 */
  132. #define TIMESTAMP            /* Can do file dates */
  133. #include <sys/time.h>
  134. #include <sys/timeb.h>
  135.  
  136. #else
  137.  
  138. #ifdef BSD4                /* BSD 4.3 and below */
  139. #define TIMESTAMP            /* Can do file dates */
  140. #include <time.h>            /* Need this */
  141. #include <sys/timeb.h>            /* Need this if really BSD */
  142.  
  143. #else
  144.  
  145. #ifdef SVORPOSIX
  146. #ifndef TIMESTAMP
  147. #define TIMESTAMP
  148. #endif /* TIMESTAMP */
  149. #include <time.h>
  150.  
  151. /* void tzset(); (the "void" type upsets some compilers) */
  152. #ifndef ultrix
  153. #ifndef CONVEX9
  154. /* ConvexOS 9.0, supposedly POSIX, has extern char *timezone(int,int) */
  155. extern long timezone;
  156. #endif /* CONVEX9 */
  157. #endif /* ultrix */
  158. #endif /* SVORPOSIX */
  159. #endif /* BSD4 */
  160. #endif /* BSD44 */
  161.  
  162. /* Is `y' a leap year? */
  163. #define leap(y) (((y) % 4 == 0 && (y) % 100 != 0) || (y) % 400 == 0)
  164.  
  165. /* Number of leap years from 1970 to `y' (not including `y' itself). */
  166. #define nleap(y) (((y) - 1969) / 4 - ((y) - 1901) / 100 + ((y) - 1601) / 400)
  167.  
  168. #ifdef COMMENT /* not used */
  169. /* Number of days in each month of the year. */
  170. static char monlens[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
  171. #endif /* COMMENT */
  172.  
  173. #ifdef CIE
  174. #include <stat.h>            /* File status */
  175. #else
  176. #include <sys/stat.h>
  177.  
  178. #ifdef OS2
  179. #include <sys/types.h>
  180. /* because standard stat has trouble with trailing /'s we have to wrap it */
  181. int os2stat(char *, struct stat *);
  182. #ifdef __IBMC__
  183. #ifdef system
  184. #undef system
  185. #endif
  186. #ifdef stat
  187. #undef stat
  188. #define __IBMC__STAT
  189. #endif
  190. #endif
  191. #define stat(path, buf) os2stat(path, buf)
  192. #endif /* OS2 */
  193. #endif /* CIE */
  194.  
  195. /*
  196.   Functions (n is one of the predefined file numbers from ckcker.h):
  197.  
  198.    zopeni(n,name)   -- Opens an existing file for input.
  199.    zopeno(n,name,attr,fcb) -- Opens a new file for output.
  200.    zclose(n)        -- Closes a file.
  201.    zchin(n,&c)      -- Gets the next character from an input file.
  202.    zsinl(n,&s,x)    -- Read a line from file n, max len x, into address s.
  203.    zsout(n,s)       -- Write a null-terminated string to output file, buffered.
  204.    zsoutl(n,s)      -- Like zsout, but appends a line terminator.
  205.    zsoutx(n,s,x)    -- Write x characters to output file, unbuffered.
  206.    zchout(n,c)      -- Add a character to an output file, unbuffered.
  207.    zchki(name)      -- Check if named file exists and is readable, return size.
  208.    zchko(name)      -- Check if named file can be created.
  209.    zchkspa(name,n)  -- Check if n bytes available to create new file, name.
  210.    znewn(name,s)    -- Make a new unique file name based on the given name.
  211.    zdelet(name)     -- Delete the named file.
  212.    zxpand(string)   -- Expands the given wildcard string into a list of files.
  213.    znext(string)    -- Returns the next file from the list in "string".
  214.    zxcmd(n,cmd)     -- Execute the command in a lower fork on file number n.
  215.    zclosf()         -- Close input file associated with zxcmd()'s lower fork.
  216.    zrtol(n1,n2)     -- Convert remote filename into local form.
  217.    zltor(n1,n2)     -- Convert local filename into remote form.
  218.    zchdir(dirnam)   -- Change working directory.
  219.    zhome()          -- Return pointer to home directory name string.
  220.    zkself()         -- Kill self, log out own job.
  221.    zsattr(struct zattr *) -- Return attributes for file which is being sent.
  222.    zstime(f, struct zattr *, x) - Set file creation date from attribute packet.
  223.    zrename(old, new) -- Rename a file.
  224.  */
  225.  
  226. /* Kermit-specific includes */
  227. /*
  228.   Definitions here supersede those from system include files.
  229.   ckcdeb.h is included above.
  230. */
  231. #include "ckcker.h"            /* Kermit definitions */
  232. #include "ckucmd.h"            /* For sys-dependent keyword tables */
  233. #include "ckuver.h"            /* Version herald */
  234.  
  235. char *ckzsys = HERALD;
  236.  
  237. /*
  238.   File access checking ...  There are two calls to access() in this module.
  239.   If this program is installed setuid or setgid on a Berkeley-based UNIX
  240.   system that does NOT incorporate the saved-original-effective-uid/gid
  241.   feature, then, when we have swapped the effective and original uid/gid,
  242.   access() fails because it uses what it thinks are the REAL ids, but we have
  243.   swapped them.  This occurs on systems where ANYBSD is defined, NOSETREU
  244.   is NOT defined, and SAVEDUID is NOT defined.  So, in theory, we should take
  245.   care of this situation like so:
  246.  
  247.     ifdef ANYBSD
  248.     ifndef NOSETREU
  249.     ifndef SAVEDUID
  250.     define SW_ACC_ID
  251.     endif
  252.     endif
  253.     endif
  254.  
  255.   But we can't test such a general scheme everywhere, so let's only do this
  256.   when we know we have to...
  257. */
  258. #ifdef NEXT                /* NeXTSTEP 1.0-3.0 */
  259. #define SW_ACC_ID
  260. #endif /* NEXT */
  261.  
  262. /* Support for tilde-expansion in file and directory names */
  263.  
  264. #ifdef POSIX
  265. #define NAMEENV "LOGNAME"
  266. #endif /* POSIX */
  267.  
  268. #ifdef BSD4
  269. #define NAMEENV "USER"
  270. #endif /* BSD4 */
  271.  
  272. #ifdef ATTSV
  273. #define NAMEENV "LOGNAME"
  274. #endif /* ATTSV */
  275.  
  276. /* Berkeley Unix Version 4.x */
  277. /* 4.1bsd support from Charles E Brooks, EDN-VAX */
  278.  
  279. #ifdef BSD4
  280. #ifdef MAXNAMLEN
  281. #define BSD42
  282. #endif /* MAXNAMLEN */
  283. #endif /* BSD4 */
  284.  
  285. /* Definitions of some system commands */
  286.  
  287. #ifdef OS2
  288. char *DELCMD = "del ";            /* For file deletion */
  289. char *PWDCMD = "chdir ";        /* For saying where I am */
  290. char *TYPCMD = "type ";            /* For typing a file */
  291. char *DIRCMD = "dir ";            /* For directory listing */
  292. char *DIRCM2 = "dir ";            /* For directory listing, no args */
  293. char *WHOCMD = "";            /* Who's there? */
  294. char *SPACMD = "dir | find \"bytes free\""; /* For space on disk */
  295. char *SPACM2 = "dir | find \"bytes free\""; /* For space on disk */
  296.  
  297. #else /* Not OS2, ergo UNIX */
  298.  
  299. char *DELCMD = "rm -f ";        /* For file deletion */
  300. char *PWDCMD = "pwd ";            /* For saying where I am */
  301. #ifdef COMMENT
  302. char *DIRCMD = "/bin/ls -ld ";        /* For directory listing */
  303. char *DIRCM2 = "/bin/ls -ld *";        /* For directory listing, no args */
  304. #else
  305. char *DIRCMD = "/bin/ls -l ";        /* For directory listing */
  306. char *DIRCM2 = "/bin/ls -l ";        /* For directory listing, no args */
  307. #endif /* COMMENT */
  308. char *TYPCMD = "cat ";            /* For typing a file */
  309.  
  310. #ifdef FT18                /* Fortune For:Pro 1.8 */
  311. #undef BSD4
  312. #endif /* FT18 */
  313.  
  314. #ifdef BSD4
  315. char *SPACMD = "pwd ; df .";        /* Space in current directory */
  316. #else
  317. #ifdef FT18
  318. char *SPACMD = "pwd ; du ; df .";
  319. #else
  320. char *SPACMD = "df ";
  321. #endif /* FT18 */
  322. #endif /* BSD4 */
  323.  
  324. char *SPACM2 = "df ";            /* For space in specified directory */
  325.  
  326. #ifdef FT18
  327. #define BSD4
  328. #endif /* FT18 */
  329.  
  330. #ifdef BSD4
  331. char *WHOCMD = "finger ";
  332. #else
  333. char *WHOCMD = "who ";
  334. #endif /* BSD4 */
  335.  
  336. #endif /* OS2 */
  337.  
  338. #ifdef DTILDE                /* For tilde expansion */
  339. _PROTOTYP( char * tilde_expand, (char *) );
  340. #endif /* DTILDE */
  341.  
  342. /* More system-dependent includes, which depend on symbols defined */
  343. /* in the Kermit-specific includes.  Oh what a tangled web we weave... */
  344.  
  345. #ifdef COHERENT                /* <sys/file.h> */
  346. #define NOFILEH
  347. #endif /* COHERENT */
  348.  
  349. #ifdef MINIX
  350. #define NOFILEH
  351. #endif /* MINIX */
  352.  
  353. #ifdef aegis
  354. #define NOFILEH
  355. #endif /* aegis */
  356.  
  357. #ifdef unos
  358. #define NOFILEH
  359. #endif /* unos */
  360.  
  361. #ifndef NOFILEH
  362. #include <sys/file.h>
  363. #endif /* NOFILEH */
  364.  
  365. #ifndef is68k                /* Whether to include <fcntl.h> */
  366. #ifndef BSD41                /* All but a couple UNIXes have it. */
  367. #ifndef FT18
  368. #ifndef COHERENT
  369. #include <fcntl.h>
  370. #endif /* COHERENT */
  371. #endif /* FT18  */
  372. #endif /* BSD41 */
  373. #endif /* not is68k */
  374.  
  375. #ifdef COHERENT
  376. #ifdef _I386
  377. #include <fcntl.h>
  378. #else
  379. #include <sys/fcntl.h>
  380. #endif /* _I386 */
  381. #endif /* COHERENT */
  382.  
  383. /*
  384.   Change argument to "(const char *)" if this causes trouble.
  385.   Or... if it causes trouble, then maybe it was already declared 
  386.   in a header file after all, so you can remove this prototype.
  387. */
  388. #ifndef _POSIX_SOURCE
  389. #ifndef NEXT
  390. #ifndef SVR4
  391. /* POSIX <pwd.h> already gave prototypes for these. */
  392. #ifdef IRIX40
  393. _PROTOTYP( struct passwd * getpwnam, (const char *) );
  394. #else
  395. _PROTOTYP( struct passwd * getpwnam, (char *) );
  396. #endif /* IRIX40 */
  397. #ifndef SUNOS4
  398. _PROTOTYP( struct passwd * getpwuid, (PWID_T) );
  399. #endif /* SUNOS4 */
  400. _PROTOTYP( struct passwd * getpwent, (void) );
  401. #endif /* SVR4 */
  402. #endif /* NEXT */
  403. #endif /* _POSIX_SOURCE */
  404.  
  405. /* Define macros for getting file type */
  406.  
  407. #ifdef OXOS
  408. /*
  409.   Olivetti X/OS 2.3 has S_ISREG and S_ISDIR defined
  410.   incorrectly, so we force their redefinition.
  411. */
  412. #undef S_ISREG
  413. #undef S_ISDIR
  414. #endif /* OXOS */
  415.  
  416. #ifdef UTSV                /* Same deal for Amdahl UTSV */
  417. #undef S_ISREG
  418. #undef S_ISDIR
  419. #endif /* UTSV */
  420.  
  421. #ifdef UNISYS52                /* And for UNISYS UTS V 5.2 */
  422. #undef S_ISREG
  423. #undef S_ISDIR
  424. #endif /* UNISYS52 */
  425.  
  426. #ifndef S_ISREG
  427. #define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
  428. #endif /* S_ISREG */
  429. #ifndef S_ISDIR
  430. #define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
  431. #endif /* S_ISDIR */
  432.  
  433. /* Define maximum length for a file name if not already defined */
  434.  
  435. #ifndef MAXNAMLEN
  436. #ifdef sun
  437. #define MAXNAMLEN 255
  438. #else
  439. #ifdef FILENAME_MAX
  440. #define MAXNAMLEN FILENAME_MAX
  441. #else
  442. #ifdef NAME_MAX
  443. #define MAXNAMLEN NAME_MAX
  444. #else
  445. #ifdef _POSIX_NAME_MAX
  446. #define MAXNAMLEN _POSIX_NAME_MAX
  447. #else
  448. #ifdef _D_NAME_MAX
  449. #define MAXNAMLEN _D_NAME_MAX
  450. #else
  451. #ifdef DIRSIZ
  452. #define MAXNAMLEN DIRSIZ
  453. #else
  454. #define MAXNAMLEN 14
  455. #endif /* DIRSIZ */
  456. #endif /* _D_NAME_MAX */
  457. #endif /* _POSIX_NAME_MAX */
  458. #endif /* NAME_MAX */
  459. #endif /* FILENAME_MAX */
  460. #endif /* sun */
  461. #endif /* MAXNAMLEN */
  462.  
  463. /* Longest pathname */
  464.  
  465. #ifdef MAXPATHLEN
  466. #ifdef MAXPATH
  467. #undef MAXPATH
  468. #endif /* MAXPATH */
  469. #define MAXPATH MAXPATHLEN
  470. #else
  471. #ifdef PATH_MAX
  472. #define MAXPATH PATH_MAX
  473. #else
  474. #ifdef _POSIX_PATH_MAX
  475. #define MAXPATH _POSIX_PATH_MAX
  476. #else
  477. #ifdef BSD42
  478. #define MAXPATH 1024
  479. #else
  480. #define MAXPATH 255
  481. #endif /* BSD42 */
  482. #endif /* _POSIX_PATH_MAX */
  483. #endif /* PATH_MAX */
  484. #endif /* MAXPATHLEN */
  485.  
  486. /* Maximum number of filenames for wildcard expansion */
  487.  
  488. #ifdef PROVX1
  489. #define MAXWLD 50
  490. #else
  491. #ifdef BSD29
  492. #define MAXWLD 50
  493. #else
  494. #ifdef pdp11
  495. #define MAXWLD 50
  496. #else
  497. #define MAXWLD 1000
  498. #endif /* pdp11 */
  499. #endif /* BSD29 */
  500. #endif /* PROVX1 */
  501.  
  502. /* More internal function prototypes */
  503. /*
  504.  * The path structure is used to represent the name to match.
  505.  * Each slash-separated segment of the name is kept in one
  506.  * such structure, and they are linked together, to make
  507.  * traversing the name easier.
  508.  */
  509. struct path {
  510.     char npart[MAXNAMLEN+4];        /* name part of path segment */
  511.     struct path *fwd;            /* forward ptr */
  512. };
  513. _PROTOTYP( int shxpand, (char *, char *[], int ) );
  514. _PROTOTYP( static int fgen, (char *, char *[], int ) );
  515. _PROTOTYP( static VOID traverse, (struct path *, char *, char *) );
  516. _PROTOTYP( static VOID addresult, (char *) );
  517. _PROTOTYP( static int match, (char *, char *) );
  518. _PROTOTYP( static char * whoami, (void) );
  519. _PROTOTYP( char * xindex, (char *, char) );
  520. _PROTOTYP( UID_T real_uid, (void) );
  521. _PROTOTYP( struct path *splitpath, (char *p) );
  522.  
  523. /* Some systems define these symbols in include files, others don't... */
  524.  
  525. #ifndef R_OK
  526. #define R_OK 4                /* For access */
  527. #endif
  528.  
  529. #ifndef W_OK
  530. #define W_OK 2
  531. #endif
  532.  
  533. #ifndef O_RDONLY
  534. #define O_RDONLY 000
  535. #endif
  536.  
  537. /* Declarations */
  538.  
  539. int maxnam = MAXNAMLEN;            /* Available to the outside */
  540. int maxpath = MAXPATH;
  541.  
  542. FILE *fp[ZNFILS] = {             /* File pointers */
  543.     NULL, NULL, NULL, NULL, NULL, NULL, NULL };
  544. #ifdef OS2
  545. int ispipe[ZNFILS];            /* Flag for file is a pipe */
  546. #endif /* OS2 */
  547.  
  548. /* Buffers and pointers used in buffered file input and output. */
  549. #ifdef DYNAMIC
  550. extern char *zinbuffer, *zoutbuffer;
  551. #else
  552. extern char zinbuffer[], zoutbuffer[];
  553. #endif /* DYNAMIC */
  554. extern char *zinptr, *zoutptr;
  555. extern int zincnt, zoutcnt;
  556. extern int wildxpand;
  557.  
  558. extern UID_T real_uid();
  559.  
  560. static long iflen = -1L;        /* Input file length */
  561.  
  562. static PID_T pid = 0;            /* pid of child fork */
  563. static int fcount;            /* Number of files in wild group */
  564. static char nambuf[MAXNAMLEN+4];    /* Buffer for a filename */
  565. #ifndef NOFRILLS
  566. static char zmbuf[200];            /* For mail, remote print strings */
  567. #endif /* NOFRILLS */
  568.  
  569. /* static */                /* Not static, must be global now. */
  570. char *mtchs[MAXWLD],            /* Matches found for filename */
  571.      **mtchptr;                /* Pointer to current match */
  572.  
  573. /*  Z K S E L F  --  Kill Self: log out own job, if possible.  */
  574.  
  575. /* Note, should get current pid, but if your system doesn't have */
  576. /* getppid(), then just kill(0,9)...  */
  577.  
  578. #ifndef SVR3
  579. #ifndef POSIX
  580. #ifndef OSFPC
  581. /* Already declared in unistd.h for SVR3 and POSIX */
  582. #ifdef CK_ANSIC
  583. extern PID_T getppid(void);
  584. #else
  585. #ifndef PS2AIX10
  586. extern PID_T getppid();
  587. #endif /* PS2AIX10 */
  588. #endif /* CK_ANSIC */
  589. #endif /* OSFPC */
  590. #endif /* POSIX */
  591. #endif /* SVR3 */
  592. int
  593. zkself() {                /* For "bye", but no guarantee! */
  594. #ifdef PROVX1
  595.     return(kill(0,9));
  596. #else
  597. #ifdef V7
  598.     return(kill(0,9));
  599. #else
  600. #ifdef TOWER1
  601.     return(kill(0,9));
  602. #else
  603. #ifdef FT18
  604.     return(kill(0,9));
  605. #else
  606. #ifdef aegis
  607.     return(kill(0,9));
  608. #else
  609. #ifdef COHERENT
  610.     return(kill((PID_T)getpid(),1));
  611. #else
  612. #ifdef OS2
  613.     exit(3);
  614. #else
  615. #ifdef PID_T
  616.     exit(kill((PID_T)getppid(),1));
  617. #else
  618.     exit(kill(getppid(),1));
  619. #endif
  620. #endif
  621. #endif
  622. #endif
  623. #endif
  624. #endif
  625. #endif
  626. #endif
  627. }
  628.  
  629. /*  Z O P E N I  --  Open an existing file for input. */
  630.  
  631. int
  632. zopeni(n,name) int n; char *name; {
  633.     debug(F111," zopeni",name,n);
  634.     debug(F101,"  fp","", fp[n]);
  635.     if (chkfn(n) != 0) return(0);
  636.     zincnt = 0;                /* Reset input buffer */
  637.     if (n == ZSYSFN) {            /* Input from a system function? */
  638. /*** Note, this function should not be called with ZSYSFN ***/
  639. /*** Always call zxcmd() directly, and give it the real file number ***/
  640. /*** you want to use.  ***/
  641.         debug(F110,"zopeni called with ZSYSFN, failing!",name,0);
  642.     *nambuf = '\0';            /* No filename. */
  643.     return(0);            /* fail. */
  644. #ifdef COMMENT
  645.     return(zxcmd(n,name));        /* Try to fork the command */
  646. #endif
  647.     }
  648.     if (n == ZSTDIO) {            /* Standard input? */
  649.     if (isatty(0)) {
  650.         fprintf(stderr,"Terminal input not allowed");
  651.         debug(F110,"zopeni: attempts input from unredirected stdin","",0);
  652.         return(0);
  653.     }
  654.     fp[ZIFILE] = stdin;
  655. #ifdef OS2
  656.     setmode(fileno(stdin),O_BINARY);
  657. #endif /* OS2 */
  658.     return(1);
  659.     }
  660. #ifdef OS2
  661.     if (n == ZIFILE || n == ZRFILE)
  662.       fp[n] = fopen(name,"rb");        /* Binary mode */
  663.     else
  664. #endif /* OS2 */
  665.       fp[n] = fopen(name,"r");        /* Real file, open it. */
  666.     debug(F111," zopeni", name, fp[n]);
  667.     if (fp[n] == NULL) perror("zopeni");
  668.     return((fp[n] != NULL) ? 1 : 0);
  669. }
  670.  
  671. /*  Z O P E N O  --  Open a new file for output.  */
  672.  
  673. int
  674. zopeno(n,name,zz,fcb)
  675. /* zopeno */  int n; char *name; struct zattr *zz; struct filinfo *fcb; {
  676.  
  677.     char p[8];                /* (===OS2 change===) */
  678.  
  679. /* As of Version 5A, the attribute structure and the file information */
  680. /* structure are included in the arglist. */
  681.  
  682. #ifdef DEBUG
  683.     debug(F111,"zopeno",name,n);
  684.     if (fcb) {
  685.     debug(F101,"zopeno fcb disp","",fcb->dsp);
  686.     debug(F101,"zopeno fcb type","",fcb->typ);
  687.     debug(F101,"zopeno fcb char","",fcb->cs);
  688.     } else {
  689.     debug(F100,"zopeno fcb is NULL","",0);
  690.     }
  691.     if (n != ZDFILE)
  692.       debug(F111," zopeno",name,n);
  693. #endif /* DEBUG */
  694.     if (chkfn(n) != 0) return(0);
  695.     if ((n == ZCTERM) || (n == ZSTDIO)) {   /* Terminal or standard output */
  696.     fp[ZOFILE] = stdout;
  697. #ifdef DEBUG
  698.     if (n != ZDFILE)
  699.       debug(F101," fp[]=stdout", "", fp[n]);
  700. #endif /* DEBUG */
  701.     zoutcnt = 0;
  702.     zoutptr = zoutbuffer;
  703.     return(1);
  704.     }
  705.  
  706. /* A real file.  Open it in desired mode (create or append). */
  707.  
  708.     strcpy(p,"w");            /* Assume write/create mode */
  709.     if (fcb) {                /* If called with an FCB... */
  710.     if (fcb->dsp == XYFZ_A)        /* Does it say Append? */
  711.       strcpy(p,"a");        /* Yes. */
  712.     }
  713. #ifdef OS2
  714.     if (n == ZOFILE || n == ZSFILE)    /* OS/2 binary mode */
  715.       strcat(p,"b");
  716. #endif /* OS2 */
  717.     fp[n] = fopen(name,p);        /* Try to open the file */
  718.  
  719.     if (fp[n] == NULL) {        /* Failed */
  720.     debug(F101,"zopeno failed errno","",errno);
  721. #ifdef COMMENT                /* Let upper levels print message. */
  722.         perror("Can't open output file");
  723. #endif /* COMMENT */
  724.     } else {                /* Succeeded */
  725.         if (n == ZDFILE)        /* If it's the debug log */
  726.       setbuf(fp[n],NULL);        /* make it unbuffered */
  727.     else
  728.       debug(F100, "zopeno ok", "", 0);
  729.     }
  730.     zoutcnt = 0;            /* (PWP) reset output buffer */
  731.     zoutptr = zoutbuffer;
  732.     return((fp[n] != NULL) ? 1 : 0);
  733. }
  734.  
  735. /*  Z C L O S E  --  Close the given file.  */
  736.  
  737. /*  Returns 0 if arg out of range, 1 if successful, -1 if close failed.  */
  738.  
  739. int
  740. zclose(n) int n; {
  741.     int x, x2;
  742.     if (chkfn(n) < 1) return(0);    /* Check range of n */
  743.  
  744.     if ((n == ZOFILE) && (zoutcnt > 0))    /* (PWP) output leftovers */
  745.       x2 = zoutdump();
  746.     else
  747.       x2 = 0;
  748.  
  749.     x = 0;                /* Initialize return code */
  750.     if (fp[ZSYSFN]) {            /* If file is really pipe */
  751.         x = zclosf(n);            /* do it specially */
  752.     } else {
  753.         if ((fp[n] != stdout) && (fp[n] != stdin)) x = fclose(fp[n]);
  754.     fp[n] = NULL;
  755.     }
  756.     iflen = -1L;            /* Invalidate file length */
  757.     if (x == EOF)            /* if we got a close error */
  758.       return(-1);
  759.     else if (x2 < 0)        /* or an error flushing the last buffer */
  760.       return(-1);        /* then return an error */
  761.     else
  762.       return(1);
  763. }
  764.  
  765. /*  Z C H I N  --  Get a character from the input file.  */
  766.  
  767. /*  Returns -1 if EOF, 0 otherwise with character returned in argument  */
  768.  
  769. int
  770. zchin(n,c) int n; int *c; {
  771.     int a, x;
  772.  
  773.     /* (PWP) Just in case this gets called when it shouldn't. */
  774.     if (n == ZIFILE) {
  775.     x = zminchar();
  776.     *c = x;
  777.     return(x);
  778.     }
  779.     /* if (chkfn(n) < 1) return(-1); */
  780.     a = getc(fp[n]);
  781.     if (a == EOF) return(-1);
  782. #ifdef OS2
  783.     if (!binary && a == 0x1A)        /* Ctrl-Z marks EOF for text mode*/
  784.       return(-1);
  785. #endif
  786.     *c = (CHAR) a & 0377;
  787.     return(0);
  788. }
  789.  
  790. /*  Z S I N L  --  Read a line from a file  */
  791.  
  792. /*
  793.   Writes the line into the address provided by the caller.
  794.   n is the Kermit "channel number".
  795.   Writing terminates when newline is encountered, newline is not copied.
  796.   Writing also terminates upon EOF or if length x is exhausted.
  797.   Returns 0 on success, -1 on EOF or error.
  798. */
  799. int
  800. zsinl(n,s,x) int n, x; char *s; {
  801.     int a, z = 0;            /* z is return code. */
  802.  
  803.     if (chkfn(n) < 1) {            /* Make sure file is open */
  804.     return(-1);
  805.     }
  806.     a = -1;                /* Current character, none yet. */
  807.     while (x--) {            /* Up to given length */
  808. #ifndef NLCHAR
  809.     int old;
  810.     old = a;            /* Previous character */
  811. #endif
  812.     if (zchin(n,&a) < 0) {        /* Read a character from the file */
  813.         debug(F101,"zsinl","",a);
  814.         z = -1;            /* EOF or other error */
  815.         break;
  816.     }
  817. #ifdef NLCHAR
  818.     if (a == (char) NLCHAR) break;    /* Single-character line terminator */
  819. #else                    /* CRLF line terminator */
  820.     if (a == '\015') continue;    /* CR, get next character */
  821.     if (old == '\015') {        /* Previous character was CR */
  822.         if (a == '\012') break;    /* This one is LF, so we have a line */
  823.         else *s++ = '\015';        /* Not LF, deposit CR */
  824.     }
  825. #ifdef OS2
  826. /*
  827.   I'm not sure I understand this one, so let's keep it only for OS/2 for now.
  828. */
  829.     if (a == '\012') break;        /* Break on single LF too */
  830. #endif /* OS2 */
  831. #endif /* NLCHAR */
  832.     *s = a;                /* Deposit character */
  833.     s++;
  834.     }
  835.     *s = '\0';                /* Terminate the string */
  836.     return(z);
  837. }
  838.  
  839. /*
  840.  * (PWP) (re)fill the buffered input buffer with data.  All file input
  841.  * should go through this routine, usually by calling the zminchar()
  842.  * macro (in ckcker.h).
  843.  */
  844.  
  845. /*
  846.  * Suggestion: if fread() returns 0, call ferror to find out what the
  847.  * problem was.  If it was not EOF, then return -2 instead of -1.
  848.  * Upper layers (getpkt function in ckcfns.c) should set cxseen flag
  849.  * if it gets -2 return from zminchar macro.
  850.  */
  851. int
  852. zinfill() {
  853.     int x;
  854.  
  855.     errno = 0;
  856.     zincnt = fread(zinbuffer, sizeof (char), INBUFSIZE, fp[ZIFILE]);
  857. #ifdef COMMENT
  858.     debug(F101,"zinfill fp","",fp[ZIFILE]);
  859.     debug(F101,"zinfill zincnt","",zincnt);
  860. #endif
  861.     if (zincnt == 0) {
  862. #ifndef UTEK
  863. #ifdef ferror
  864.     x = ferror(fp[ZIFILE]);
  865.     debug(F101,"zinfill errno","",errno);
  866.     debug(F101,"zinfill ferror","",x);
  867.     if (x) return(-2);
  868. #endif /* ferror */
  869. #else
  870.      x = feof(fp[ZIFILE]);
  871.      debug(F101,"zinfill errno","",errno);
  872.      debug(F101,"zinfill feof","",x);
  873.      if (!x && ferror(fp[ZIFILE])) return(-2);
  874. #endif /* UTEK */
  875.     return(-1);
  876.     }
  877.     zinptr = zinbuffer;       /* set pointer to beginning, (== &zinbuffer[0]) */
  878.     zincnt--;            /* one less char in buffer */
  879.     return((int)(*zinptr++) & 0377); /* because we return the first */
  880. }
  881.  
  882. /*  Z S O U T  --  Write a string out to the given file, buffered.  */
  883.  
  884. int
  885. zsout(n,s) int n; char *s; {
  886.     if (chkfn(n) < 1) return(-1); /* Keep this here, prevents memory faults */
  887. #ifndef OS2
  888.     if (n == ZSFILE)
  889.     return(write(fileno(fp[n]),s,(int)strlen(s)));
  890.     else
  891. #endif /* OS2 */
  892.         return(fputs(s,fp[n]) == EOF ? -1 : 0);
  893. }
  894.  
  895. /*  Z S O U T L  --  Write string to file, with line terminator, buffered  */
  896.  
  897. int
  898. zsoutl(n,s) int n; char *s; {
  899.     /* if (chkfn(n) < 1) return(-1); */
  900.     if (fputs(s,fp[n]) == EOF) return(-1);
  901.     if (fputs("\n",fp[n]) == EOF) return(-1); /* (===OS2 ? \r\n) */
  902.     return(0);
  903. }
  904.  
  905. /*  Z S O U T X  --  Write x characters to file, unbuffered.  */
  906.  
  907. int
  908. zsoutx(n,s,x) int n, x; char *s; {
  909. #ifdef COMMENT
  910.     if (chkfn(n) < 1) return(-1);
  911.     return(write(fp[n]->_file,s,x));
  912. #endif
  913.     return(write(fileno(fp[n]),s,x) == x ? x : -1);
  914. }
  915.  
  916.  
  917. /*  Z C H O U T  --  Add a character to the given file.  */
  918.  
  919. /*  Should return 0 or greater on success, -1 on failure (e.g. disk full)  */
  920.  
  921. int
  922. #ifdef CK_ANSIC
  923. zchout(register int n, char c)
  924. #else
  925. zchout(n,c) register int n; char c;
  926. #endif /* CK_ANSIC */
  927. /* zchout() */ {
  928.     /* if (chkfn(n) < 1) return(-1); */
  929. #ifndef OS2
  930.     if (n == ZSFILE) {            /* Use unbuffered for session log */
  931.         return(write(fileno(fp[n]),&c,1) == 1 ? 0 : -1);
  932.     } else {                /* Buffered for everything else */
  933. #endif /* OS2 */
  934.     if (putc(c,fp[n]) == EOF)    /* If true, maybe there was an error */
  935.       return(ferror(fp[n])?-1:0);    /* Check to make sure */
  936.     else                /* Otherwise... */
  937.       return(0);            /* There was no error. */
  938. #ifndef OS2
  939.     }
  940. #endif /* OS2 */
  941. }
  942.  
  943. /* (PWP) buffered character output routine to speed up file IO */
  944.  
  945. int
  946. zoutdump() {
  947.     int x;
  948.     zoutptr = zoutbuffer;        /* Reset buffer pointer in all cases */
  949.     debug(F101,"zoutdump chars","",zoutcnt);
  950.     if (zoutcnt == 0) {            /* Nothing to output */
  951.     return(0);
  952.     } else if (zoutcnt < 0) {        /* Unexpected negative argument */
  953.     zoutcnt = 0;            /* Reset output buffer count */
  954.     return(-1);            /* and fail. */
  955.     }
  956.  
  957. /* Frank Prindle suggested that replacing this fwrite() by an fflush() */
  958. /* followed by a write() would improve the efficiency, especially when */
  959. /* writing to stdout.  Subsequent tests showed a 5-fold improvement!   */
  960. /* if (x = fwrite(zoutbuffer, 1, zoutcnt, fp[ZOFILE])) {              */
  961.  
  962.     fflush(fp[ZOFILE]);
  963.     if ((x = write(fileno(fp[ZOFILE]),zoutbuffer,zoutcnt)) == zoutcnt) {
  964.     debug(F101,"zoutdump write ok","",zoutcnt);
  965.     zoutcnt = 0;            /* Reset output buffer count */
  966.     return(0);            /* write() worked OK */
  967.     } else {
  968.     debug(F101,"zoutdump write error","",errno);
  969.     debug(F101,"zoutdump write returns","",x);
  970.     zoutcnt = 0;            /* Reset output buffer count */
  971.     return(-1);            /* write() failed */
  972.     }
  973. }
  974.  
  975. /*  C H K F N  --  Internal function to verify file number is ok  */
  976.  
  977. /*
  978.  Returns:
  979.   -1: File number n is out of range
  980.    0: n is in range, but file is not open
  981.    1: n in range and file is open
  982. */
  983. int
  984. chkfn(n) int n; {
  985. #ifdef COMMENT                /* Save some stack space */
  986.     switch (n) {
  987.     case ZCTERM:
  988.     case ZSTDIO:
  989.     case ZIFILE:
  990.     case ZOFILE:
  991.     case ZDFILE:
  992.     case ZTFILE:
  993.     case ZPFILE:
  994.     case ZSFILE:
  995.     case ZSYSFN:
  996.         case ZRFILE:
  997.         case ZWFILE: break;
  998.     default:
  999.         debug(F101,"chkfn: file number out of range","",n);
  1000.         fprintf(stderr,"?File number out of range - %d\n",n);
  1001.         return(-1);
  1002.     }
  1003.     return( (fp[n] == NULL) ? 0 : 1 );
  1004. #else
  1005.     if (n < 0 || n >= ZNFILS)
  1006.       return(-1);
  1007.     else return( (fp[n] == NULL) ? 0 : 1 );
  1008. #endif /* COMMENT */
  1009. }
  1010.  
  1011. /*  Z C H K I  --  Check if input file exists and is readable  */
  1012.  
  1013. /*
  1014.   Returns:
  1015.    >= 0 if the file can be read (returns the size).
  1016.      -1 if file doesn't exist or can't be accessed,
  1017.      -2 if file exists but is not readable (e.g. a directory file).
  1018.      -3 if file exists but protected against read access.
  1019. */
  1020. /*
  1021.  For Berkeley Unix, a file must be of type "regular" to be readable.
  1022.  Directory files, special files, and symbolic links are not readable.
  1023. */
  1024. long
  1025. zchki(name) char *name; {
  1026.     struct stat buf;
  1027.     int x;
  1028.  
  1029. #ifdef UNIX
  1030.     x = strlen(name);
  1031.     if (x == 9 && !strcmp(name,"/dev/null"))
  1032.       return(0);
  1033. #endif /* UNIX */
  1034.  
  1035.     x = stat(name,&buf);
  1036.     if (x < 0) {
  1037.     debug(F111,"zchki stat fails",name,errno);
  1038.     return(-1);
  1039.     }
  1040.     if (!S_ISREG (buf.st_mode)) {    /* Must be regular file */
  1041.     debug(F111,"zchki skipping:",name,x);
  1042.     return(-2);
  1043.     }
  1044.     debug(F111,"zchki stat ok:",name,x);
  1045.  
  1046. #ifdef SW_ACC_ID
  1047.     debug(F100,"zchki swapping ids for access()","",0);
  1048.     priv_on();
  1049. #endif /* SW_ACC_ID */
  1050.     x = access(name,R_OK);
  1051. #ifdef SW_ACC_ID
  1052.     priv_off();
  1053.     debug(F100,"zchki swapped ids restored","",0);
  1054. #endif /* SW_ACC_ID */
  1055.     if (x < 0) {     /* Is the file accessible? */
  1056.     debug(F111," access failed:",name,x); /* No */
  1057.         return(-3);
  1058.     } else {
  1059.     iflen = buf.st_size;              /* Yes, remember size */
  1060.     strncpy(nambuf,name,MAXNAMLEN);          /* and name globally. */
  1061.     debug(F111," access ok:",name,(int) iflen);
  1062.     return( (iflen > -1L) ? iflen : 0L );
  1063.     }
  1064. }
  1065.  
  1066. /*  Z C H K O  --  Check if output file can be created  */
  1067.  
  1068. /*
  1069.  Returns -1 if write permission for the file would be denied, 0 otherwise.
  1070. */
  1071. int
  1072. zchko(name) char *name; {
  1073.     int i, x;
  1074.     char *s;
  1075.  
  1076.     if (!name) return(-1);        /* Watch out for null pointer. */
  1077.     x = (int)strlen(name);        /* Get length of filename */
  1078.     debug(F101," length","",x);
  1079.  
  1080. #ifdef UNIX
  1081. /*
  1082.   Writing to null device is OK.
  1083. */
  1084.     if (x == 9 && !strcmp(name,"/dev/null"))
  1085.       return(0);
  1086. #endif /* UNIX */
  1087.  
  1088.     s = malloc(x+3);            /* Must copy because we can't */
  1089.     if (!s) {                /* write into our argument. */
  1090.     fprintf(stderr,"Malloc error 46\n");
  1091.     return(-1);
  1092.     }
  1093.     strcpy(s,name);
  1094.  
  1095.     for (i = x; i > 0; i--)        /* Strip filename from right. */
  1096.       if (ISDIRSEP(s[i-1])) break;
  1097.     debug(F101," i","",i);
  1098.  
  1099. #ifdef COMMENT
  1100. /* X/OPEN XPG3-compliant systems fail if argument ends with "/"...  */
  1101.     if (i == 0)                /* If no path, use current directory */
  1102.       strcpy(s,"./");
  1103.     else                /* Otherwise, use given one. */
  1104.       s[i] = '\0';
  1105. #else
  1106. /* So now we use "path/." if path given, or "." if no path given. */
  1107.     s[i++] = '.';            /* Append "." to path. */
  1108.     s[i] = '\0';
  1109. #endif /* COMMENT */
  1110.  
  1111. #ifdef SW_ACC_ID
  1112.     debug(F100,"zchko swapping ids for access()","",0);
  1113.     priv_on();
  1114. #endif /* SW_ACC_ID */
  1115. #ifdef OS2                /* No unwritable directories in OS/2 */
  1116.     x = 0;
  1117. #else
  1118.     x = access(s,W_OK);            /* Check access of path. */
  1119. #endif /* OS2 */
  1120. #ifdef SW_ACC_ID
  1121.     priv_off();
  1122.     debug(F100,"zchko swapped ids restored","",0);
  1123. #endif /* SW_ACC_ID */
  1124.     if (x < 0)
  1125.       debug(F111,"zchko access failed:",s,errno);
  1126.     else
  1127.       debug(F111,"zchko access ok:",s,x);
  1128.     free(s);                /* Free temporary storage */
  1129.     return((x < 0) ? -1 : 0);        /* and return. */
  1130. }
  1131.  
  1132. /*  Z D E L E T  --  Delete the named file.  */
  1133.  
  1134. int
  1135. zdelet(name) char *name; {
  1136.     return(unlink(name));
  1137. }
  1138.  
  1139.  
  1140. /*  Z R T O L  --  Convert remote filename into local form  */
  1141.  
  1142. /*  For UNIX, this means changing uppercase letters to lowercase.  */
  1143.  
  1144. VOID
  1145. zrtol(name,name2) char *name, *name2; {
  1146.     char *p; int flag = 0;
  1147.     if (!name || !name2) return;
  1148.     debug(F101,"zrtol original name","",name);
  1149.     p = name2;
  1150.     for ( ; *name != '\0'; name++) {
  1151.     if (*name > ' ') flag = 1;    /* Strip leading blanks and controls */
  1152.     if (flag == 0 && *name < '!') continue;
  1153.         *p++ = isupper(*name) ? tolower(*name) : *name;
  1154.     }
  1155.     *p-- = '\0';            /* Terminate */
  1156.     while (*p < '!' && p > name2)    /* Strip trailing blanks & controls */
  1157.       *p-- = '\0';
  1158.     if (*name2 == '\0') strcpy(name2,"NONAME");
  1159. #ifdef OS2
  1160.     if (!IsFileNameValid(name2))
  1161.       ChangeNameForFAT(name2);
  1162. #endif /* OS2 */
  1163.     debug(F110,"zrtol new name",name2,0);
  1164. }
  1165.  
  1166.  
  1167. /*  Z S T R I P  --  Strip device & directory name from file specification */
  1168.  
  1169. /*  Strip pathname from filename "name", return pointer to result in name2 */
  1170.  
  1171. #ifdef pdp11
  1172. static char work[100];        /* buffer for use by zstrip and zltor */
  1173. #else
  1174. static char work[257];
  1175. #endif /* pdp11 */
  1176.  
  1177. VOID
  1178. zstrip(name,name2) char *name, **name2; {
  1179.     char *cp, *pp;
  1180.     debug(F110,"zstrip before",name,0);
  1181.     pp = work;
  1182. #ifdef DTILDE
  1183.     if (*name == '~') name++;
  1184. #endif /* DTILDE */
  1185.     for (cp = name; *cp != '\0'; cp++) {
  1186.         if (ISDIRSEP(*cp))
  1187.       pp = work;
  1188.     else
  1189.       *pp++ = *cp;
  1190.     }
  1191.     *pp = '\0';                /* Terminate the string */
  1192.     *name2 = work;
  1193.     debug(F110,"zstrip after",*name2,0);
  1194. }
  1195.  
  1196. /*  Z L T O R  --  Local TO Remote */
  1197.  
  1198. VOID
  1199. zltor(name,name2) char *name, *name2; {
  1200.     char *cp, *pp;
  1201.     int dc = 0;
  1202. #ifdef aegis
  1203.     char *namechars;
  1204.     int tilde = 0, bslash = 0;
  1205.  
  1206.     if ((namechars = getenv("NAMECHARS")) != NULL) {
  1207.         if (xindex(namechars, '~' ) != NULL) tilde  = '~';
  1208.         if (xindex(namechars, '\\') != NULL) bslash = '\\';
  1209.     } else {
  1210.         tilde = '~';
  1211.         bslash = '\\';
  1212.     }
  1213. #endif /* aegis */
  1214.  
  1215.     debug(F110,"zltor",name,0);
  1216.     pp = work;
  1217. #ifdef aegis
  1218.     cp = name;
  1219.     if (tilde && *cp == tilde)
  1220.         ++cp;
  1221.     for (; *cp != '\0'; cp++) {
  1222.         if (*cp == '/' || *cp == bslash) {    /* strip path name */
  1223. #else
  1224.     for (cp = name; *cp != '\0'; cp++) {    /* strip path name */
  1225.         if (ISDIRSEP(*cp)) {
  1226. #endif /* aegis */
  1227.         dc = 0;
  1228.         pp = work;
  1229.     }
  1230.     else if (islower(*cp)) *pp++ = toupper(*cp); /* Uppercase letters */
  1231.     else if (*cp == '~') *pp++ = 'X';    /* Change tilde to 'X' */
  1232.     else if (*cp == '#') *pp++ = 'X';    /* Change number sign to 'X' */
  1233.     else if ((*cp == '.') && (++dc > 1)) *pp++ = 'X'; /* & extra dots */
  1234.     else *pp++ = *cp;
  1235.     }
  1236.     *pp = '\0';                /* Tie it off. */
  1237.     cp = name2;                /* If nothing before dot, */
  1238.     if (*work == '.') *cp++ = 'X';    /* insert 'X' */
  1239.     strcpy(cp,work);
  1240.     debug(F110," name2",name2,0);
  1241. }
  1242.  
  1243.  
  1244. /*  Z C H D I R  --  Change directory  */
  1245. /*
  1246.   Call with:
  1247.     dirnam = pointer to name of directory to change to,
  1248.       which may be "" or NULL to indicate user's home directory.
  1249.   Returns:
  1250.     0 on failure
  1251.     1 on success
  1252. */
  1253. int
  1254. zchdir(dirnam) char *dirnam; {
  1255.     char *hd, *sp, *p;
  1256.  
  1257.     debug(F110,"zchdir",dirnam,0);
  1258.     if (dirnam == NULL || dirnam == "" || *dirnam == '\0') /* If arg is null */
  1259.       dirnam = zhome();            /* use user's home directory. */
  1260.     sp = dirnam;
  1261.     debug(F110,"zchdir 2",dirnam,0);
  1262.  
  1263. #ifdef DTILDE
  1264.     hd = tilde_expand(dirnam);        /* Attempt to expand tilde */
  1265.     if (*hd == '\0') hd = dirnam;    /* in directory name. */
  1266. #else
  1267.     hd = dirnam;
  1268. #endif /* DTILDE */
  1269.     debug(F110,"zchdir 3",hd,0);
  1270. #ifdef pdp11
  1271.     /* Just to save some space */
  1272.     return((chdir(hd) == 0) ? 1 : 0);
  1273. #else
  1274. #ifdef OS2
  1275.     if (isalpha(hd[0]) && hd[1] == ':') {
  1276.         if (zchdsk(hd[0]))
  1277.       return(0);
  1278.     if (hd[2] == 0)
  1279.       return(1);            /* Handle drive-only case */
  1280.     }
  1281. #endif /* OS2 */
  1282.     if (chdir(hd) == 0) return(1);    /* Try to cd */ /* (===OS2===) */
  1283.     p = sp;                /* Failed, lowercase it. */
  1284.     while (*p) {
  1285.     if (isupper(*p)) *p = tolower(*p);
  1286.     p++;
  1287.     }
  1288.     debug(F110,"zchdir 4",hd,0);
  1289. #ifdef DTILDE
  1290.     hd = tilde_expand(sp);        /* Try again to expand tilde */
  1291.     if (*hd == '\0') hd = sp;
  1292. #else
  1293.     hd = sp;                /* Point to result */
  1294. #endif /* DTILDE */
  1295.     debug(F110,"zchdir 5",hd,0);
  1296.     return((chdir(hd) == 0) ? 1 : 0);
  1297. #endif /* pdp11 */
  1298. }
  1299.  
  1300. /*  Z H O M E  --  Return pointer to user's home directory  */
  1301.  
  1302. char *
  1303. zhome() {
  1304.     char *home = getenv("HOME");
  1305. #ifdef OS2
  1306.     extern char startupdir[];
  1307.     return(home ? home : startupdir);
  1308. #else
  1309.     return(home ? home : ".");
  1310. #endif
  1311. }
  1312.  
  1313. /*  Z G T D I R  --  Return pointer to user's current directory  */
  1314.  
  1315. #ifdef pdp11
  1316. #define CWDBL 80            /* Save every byte we can... */
  1317. #else
  1318. #ifdef MAXPATHLEN
  1319. #define CWDBL MAXPATHLEN
  1320. #else
  1321. #define CWDBL 100
  1322. #endif /* MAXPATHLEN */
  1323. #endif /* pdp11 */
  1324. static char cwdbuf[CWDBL+1];
  1325.  
  1326. char *
  1327. zgtdir() {
  1328.     char *buf;
  1329.  
  1330. #ifdef BSD44
  1331.     extern char *getwd();
  1332.     buf = cwdbuf;
  1333.     return(getwd(buf));
  1334. #else
  1335. #ifdef SVORPOSIX
  1336.     extern char *getcwd();
  1337.     buf = cwdbuf;
  1338.     return(getcwd(buf,CWDBL));
  1339. #else
  1340. #ifdef COHERENT
  1341. #ifdef _I386
  1342.     extern char *getcwd();
  1343.     buf = cwdbuf;
  1344.     return(getcwd(buf,CWDBL));
  1345. #else
  1346.     extern char *getwd();
  1347.     buf = cwdbuf;
  1348.     return(getwd(buf));
  1349. #endif /* _I386 */
  1350. #else
  1351. #ifdef OS2
  1352. #ifndef __IBMC__ /* which has a macro for this */
  1353.     extern char *getcwd();
  1354. #endif /* __IBMC__ */
  1355.     buf = cwdbuf;
  1356.     return(getcwd(buf,CWDBL));
  1357. #else
  1358. #ifdef BSD4
  1359.     extern char *getwd();
  1360.     buf = cwdbuf;
  1361.     return(getwd(buf));
  1362. #else
  1363.     return("directory unknown");
  1364. #endif /* BSD4 */
  1365. #endif /* OS2 */
  1366. #endif /* COHERENT */
  1367. #endif /* SYSVORPOSIX */
  1368. #endif /* BSD44 */
  1369. }
  1370.  
  1371. /*  Z X C M D -- Run a system command so its output can be read like a file */
  1372.  
  1373. int
  1374. zxcmd(filnum,comand) int filnum; char *comand; {
  1375. #ifdef OS2
  1376.     if (chkfn(filnum) < 0) return(-1);    /* Need a valid Kermit file number. */
  1377.     if (filnum == ZSTDIO || filnum == ZCTERM) /* But not one of these. */
  1378.       return(0);
  1379.     if (filnum == ZIFILE || filnum == ZRFILE) { /* Input from a command */
  1380.     if (priv_chk() || ((fp[filnum] = popen(comand,"r")) == NULL))
  1381.       return(0);
  1382.     } else { /* Output to a command */
  1383.     if (priv_chk() || ((fp[filnum] = popen(comand,"w")) == NULL))
  1384.       return(0);
  1385.     }
  1386.     ispipe[filnum] = 1;
  1387.     return(1);
  1388. #else /* Not OS2 */
  1389.     int pipes[2];
  1390.     int out;
  1391.  
  1392.     if (chkfn(filnum) < 0) return(-1);    /* Need a valid Kermit file number. */
  1393.     if (filnum == ZSTDIO || filnum == ZCTERM) /* But not one of these. */
  1394.       return(0);
  1395.  
  1396.     out = (filnum == ZIFILE || filnum == ZRFILE) ? 0 : 1 ;
  1397.  
  1398. /* Output to a command */
  1399.  
  1400.     if (out) {                /* Need popen() to do this. */
  1401. #ifdef NOPOPEN
  1402.     return(0);            /* no popen(), fail. */
  1403. #else
  1404. /* Use popen() to run the command. */
  1405.  
  1406. #ifdef _POSIX_SOURCE
  1407. /* Strictly speaking, popen() is not available in POSIX.1 */
  1408. #define DCLPOPEN
  1409. #endif /* _POSIX_SOURCE */
  1410.  
  1411. #ifdef COHERENT
  1412. #define DCLPOPEN
  1413. FILE * fdopen();
  1414. #endif /* COHERENT */
  1415.  
  1416. #ifdef DCLPOPEN
  1417. /* popen() needs declaring because it's not declared in <stdio.h> */
  1418.     FILE *popen();
  1419. #endif /* DCLPOPEN */
  1420.  
  1421.     if (priv_chk() || ((fp[filnum] = popen(comand,"w")) == NULL))
  1422.       return(0);
  1423.     else return(1);
  1424. #endif /* NOPOPEN */
  1425.     }
  1426.  
  1427. /* Input from a command */
  1428.  
  1429.     if (pipe(pipes) != 0) {
  1430.     debug(F100,"zxcmd pipe failure","",0);
  1431.     return(0);            /* can't make pipe, fail */
  1432.     }
  1433.  
  1434. /* Create a fork in which to run the named process */
  1435.  
  1436. #ifdef aegis
  1437.     if ((pid = vfork()) == 0) {        /* child */
  1438. #else
  1439.     if ((pid = fork()) == 0) {        /* child */
  1440. #endif
  1441.  
  1442. /* We're in the fork. */
  1443.  
  1444.     char *shpath, *shname, *shptr;    /* Find user's preferred shell */
  1445. #ifndef aegis
  1446.     struct passwd *p;
  1447.     char *defshell = "/bin/sh";    /* default shell */
  1448. #endif /* aegis */
  1449.     if (priv_can()) exit(1);    /* Turn off any privileges! */
  1450.     debug(F101,"zxcmd pid","",pid);
  1451.     close(pipes[0]);        /* close input side of pipe */
  1452.     close(0);            /* close stdin */
  1453.     if (open("/dev/null",0) < 0) return(0); /* replace input by null */
  1454. #ifndef OXOS
  1455. #ifndef SVORPOSIX
  1456.     dup2(pipes[1],1);        /* BSD: replace stdout & stderr */
  1457.     dup2(pipes[1],2);        /* by the pipe */
  1458. #else
  1459.     close(1);            /* AT&T: close stdout */
  1460.     if ( dup(pipes[1]) != 1 )    /* Send stdout to the pipe */
  1461.       return(0);
  1462.     close(2);            /* Send stderr to the pipe */
  1463.     if ( dup(pipes[1]) != 2 )
  1464.       return(0);
  1465. #endif /* SVORPOSIX */
  1466. #else /* OXOS */
  1467.     dup2(pipes[1],1);
  1468.     dup2(pipes[1],2);
  1469. #endif /* OXOS */
  1470.     close(pipes[1]);        /* Don't need this any more. */
  1471.  
  1472. #ifdef aegis
  1473.     if ((shpath = getenv("SERVERSHELL")) == NULL) shpath = "/bin/sh";
  1474. #else
  1475.     shpath = getenv("SHELL");    /* What shell? */
  1476.     if (shpath == NULL) {
  1477.         p = getpwuid( real_uid() );    /* Get login data */
  1478.         if (p == (struct passwd *)NULL || !*(p->pw_shell))
  1479.           shpath = defshell;
  1480.         else shpath = p->pw_shell;
  1481.         }
  1482. #endif /* aegis */
  1483.     shptr = shname = shpath;
  1484.     while (*shptr != '\0')
  1485.       if (*shptr++ == '/')
  1486.         shname = shptr;
  1487.     debug(F100,"zxcmd...","",0);
  1488.     debug(F110,shpath,shname,0);
  1489.  
  1490.     execl(shpath,shname,"-c",comand,(char *)NULL); /* Execute the cmd */
  1491.     exit(0);            /* just punt if it failed. */
  1492.     } else if (pid == (PID_T) -1) {
  1493.     debug(F100,"zxcmd fork failure","",0);
  1494.     return(0);
  1495.     }
  1496.     debug(F101,"zxcmd pid","",pid);
  1497.     if (out) {
  1498.     close(pipes[0]);        /* Don't need the input side */
  1499.     fp[filnum] = fdopen(pipes[1],"w"); /* Open a stream for output. */
  1500.     fp[ZSYSFN] = fp[filnum];    /* Remember. */
  1501.     zoutcnt = 0;            /* (PWP) reset input buffer */
  1502.     zoutptr = zoutbuffer;
  1503.     } else {
  1504.     close(pipes[1]);        /* Don't need the output side */
  1505.     fp[filnum] = fdopen(pipes[0],"r"); /* Open a stream for input. */
  1506.     fp[ZSYSFN] = fp[filnum];    /* Remember. */
  1507.     zincnt = 0;            /* (PWP) reset input buffer */
  1508.     zinptr = zinbuffer;
  1509.     }
  1510.     return(1);
  1511. #endif /* OS2 */
  1512. }
  1513.  
  1514. /*  Z C L O S F  - wait for the child fork to terminate and close the pipe. */
  1515.  
  1516. int
  1517. zclosf(filnum) int filnum; {
  1518.     int wstat;
  1519.     debug(F101,"zclosf filnum","",filnum);
  1520. #ifndef NOPOPEN
  1521. #ifdef OS2
  1522.     if (ispipe[filnum]) {
  1523.     int x;
  1524.     x = pclose(fp[filnum]);
  1525.     fp[filnum] = NULL;
  1526.     ispipe[filnum] = 0;
  1527. #else
  1528.     if (filnum == ZWFILE) {
  1529.     int x;
  1530.     x = pclose(fp[filnum]);
  1531.     fp[filnum] = fp[ZSYSFN] = NULL;
  1532. #endif /* OS2 */
  1533.     return((x < 0) ? 0 : 1);
  1534.     }
  1535. #endif /* NOPOPEN */
  1536.     debug(F101,"zclosf fp[filnum]","", fp[filnum]);
  1537.     debug(F101,"zclosf fp[ZSYSFN]","", fp[ZSYSFN]);
  1538. #ifdef OS2
  1539.     fclose(fp[filnum]);
  1540.     fp[filnum] = NULL;
  1541. #else
  1542.     if (pid != (PID_T) 0) {
  1543.     debug(F101,"zclosf killing pid","",pid);
  1544.     kill(pid,9);
  1545.         while ((wstat = wait((WAIT_T *)0)) != pid && wstat != -1) ;
  1546.         pid = 0;
  1547.     }
  1548.     fclose(fp[filnum]);
  1549.     fp[filnum] = fp[ZSYSFN] = NULL;
  1550. #endif /* OS2 */
  1551.     return(1);
  1552. }
  1553.  
  1554. /*  Z X P A N D  --  Expand a wildcard string into an array of strings  */
  1555. /*
  1556.   Returns the number of files that match fn1, with data structures set up
  1557.   so that first file (if any) will be returned by the next znext() call.
  1558.   Depends on external variable wildxpand: 0 means we expand wildcards
  1559.   internally, nonzero means we call the shell to do it.
  1560. */
  1561.  
  1562. int
  1563. zxpand(fn) char *fn; {
  1564.     char *p;
  1565.  
  1566. #ifdef DTILDE                /* Built with tilde-expansion? */
  1567.     char *tnam;
  1568. #endif /* DTILDE */
  1569.     debug(F111,"zxpand entry",fn,wildxpand);
  1570. #ifdef DTILDE                /* Built with tilde-expansion? */
  1571.     if (*fn == '~') {            /* Starts with tilde? */
  1572.     tnam = tilde_expand(fn);    /* Try to expand it. */
  1573.     if (tnam) fn = tnam;
  1574.     }
  1575.     debug(F110,"zxpand after tilde_x",fn,0);
  1576. #endif /* DTILDE */
  1577. #ifndef OS2
  1578.     if (wildxpand)            /* Who is expanding wildcards? */
  1579.       fcount = shxpand(fn,mtchs,MAXWLD); /* Shell */
  1580.     else
  1581. #endif /* OS2 */
  1582.       fcount = fgen(fn,mtchs,MAXWLD);    /* Kermit */
  1583.     if (fcount > 0) {
  1584.     mtchptr = mtchs;        /* Save pointer for next. */
  1585.     }
  1586.     if (fcount > 0) {
  1587.     debug(F111,"zxpand ok",mtchs[0],fcount);
  1588.     return(fcount);
  1589.     }
  1590.     debug(F111,"zxpand fgen1",fn,fcount); /* Didn't get one, or got too many */
  1591.     p = malloc((int)strlen(fn) + 10);    /* Make space */
  1592.     if (!p) return(0);
  1593.     zrtol(fn,p);            /* Try again, maybe lowercase */
  1594. #ifndef OS2
  1595.     if (wildxpand)
  1596.       fcount = shxpand(p,mtchs,MAXWLD); /* Shell */
  1597.     else
  1598. #endif /* OS2 */
  1599.       fcount = fgen(p,mtchs,MAXWLD);    /* Kermit */
  1600.     if (fcount > 0) {            /* Got one? */
  1601.     mtchptr = mtchs;        /* Save pointer for next. */
  1602.     debug(F111,"zxpand fgen2 ok",mtchs[0],fcount);
  1603.     } else debug(F111,"zxpand 2 not ok",p,fcount);
  1604.     free(p);
  1605.     return(fcount);
  1606. }
  1607.  
  1608.  
  1609. /*  Z N E X T  --  Get name of next file from list created by zxpand(). */
  1610. /*
  1611.  Returns >0 if there's another file, with its name copied into the arg string,
  1612.  or 0 if no more files in list.
  1613. */
  1614. int
  1615. znext(fn) char *fn; {
  1616.     if (fcount-- > 0) strcpy(fn,*mtchptr++);
  1617.     else *fn = '\0';
  1618.     debug(F111,"znext",fn,fcount+1);
  1619.     return(fcount+1);
  1620. }
  1621.  
  1622.  
  1623. /*  Z C H K S P A  --  Check if there is enough space to store the file  */
  1624.  
  1625. /*
  1626.  Call with file specification f, size n in bytes.
  1627.  Returns -1 on error, 0 if not enough space, 1 if enough space.
  1628. */
  1629. int
  1630. #ifdef CK_ANSIC
  1631. zchkspa(char *f, long n)
  1632. #else
  1633. zchkspa(f,n) char *f; long n;
  1634. #endif /* CK_ANSIC */
  1635. /* zchkspa() */ {
  1636. #ifdef OS2
  1637. /* OS/2 gives us an easy way to do this. */
  1638.     if (isalpha(f[0]) && f[1] == ':')
  1639.       return(zdskspace(toupper(f[0]) - 'A' + 1) >= n);
  1640.     else
  1641.       return(zdskspace(0) >= n);
  1642. #else
  1643. /* In UNIX there is no good (and portable) way. */
  1644.     return(1);                /* Always say OK. */
  1645. #endif /* OS2 */
  1646. }
  1647.  
  1648.  
  1649. /*  Z N E W N  --  Make a new name for the given file  */
  1650.  
  1651. /*
  1652.   Given the name, fn, of a file that already exists, this function builds a
  1653.   new name of the form "<oldname>.~<n>~", where <oldname> is argument name
  1654.   (fn), and <n> is a version number, one higher than any existing version
  1655.   number for that file, up to 9999.  This format is consistent with that used
  1656.   by GNU EMACS.  If the constructed name is too long for the system's maximum,
  1657.   enough characters are truncated from the end of <fn> to allow the version
  1658.   number to fit.  If no free version numbers exist between 1 and 9999, a
  1659.   version number of "xxxx" is used.  Returns a pointer to the new name in
  1660.   argument s.
  1661. */
  1662.  
  1663. VOID
  1664. znewn(fn,s) char *fn, **s; {
  1665. #ifdef pdp11
  1666. #define ZNEWNBL 63            /* Name buffer length */
  1667. #define ZNEWNMD 3            /* Max digits for version number */
  1668. #else
  1669. #define ZNEWNBL 255
  1670. #define ZNEWNMD 4
  1671. #endif /* pdp11 */
  1672.  
  1673.     static char buf[ZNEWNBL+1];
  1674.     char *bp, *xp, *yp;
  1675. #ifdef OS2
  1676.     char *zp, ch, temp[14];
  1677. #endif /* OS2 */
  1678.     int len = 0, d = 0, n, t, i, j, k, power = 1;
  1679.  
  1680.     int max = MAXNAMLEN;        /* Maximum name length */
  1681.  
  1682.     if (max < 14) max = 14;        /* Make it reasonable */
  1683.     if (max > ZNEWNBL) max = ZNEWNBL;
  1684.     bp = buf;                /* Buffer for building new name */
  1685.     yp = fn;
  1686.     while (*yp) {            /* Copy old name into buffer */
  1687.     *bp++ = *yp++;
  1688.     if (len++ > ZNEWNBL) break;    /* ...up to buffer length */
  1689.     }
  1690.     *s = NULL;
  1691.     for (i = 1; i < ZNEWNMD + 1; i++) {    /* Version numbers up to 10**i - 1 */
  1692.     power *= 10;            /* Next power of 10 */
  1693.     j = max - len;            /* Space left for version number */
  1694.     k = 3 + i;            /* Space needed for it */
  1695.     if (j < k) {            /* Make room if necessary */
  1696.         len -= (k - j);        /* Adjust length of filename */
  1697.         bp = buf + len;        /* Point to new end */
  1698.     }
  1699.     *bp++ = '*';            /* Put a star on the end (UNIX) */
  1700.     *bp-- = '\0';            /* Terminate with null */
  1701.  
  1702.     n = zxpand(buf);        /* Expand the resulting wild name */
  1703.                     /* n is the number of matches */
  1704.     while (n-- > 0) {        /* Find any existing name.~n~ files */
  1705.         xp = *mtchptr++;        /* Point at matching name */
  1706.         xp += len;            /* Look for .~<n>~ at the end of it */
  1707.         if (*xp == '.' && *(xp+1) == '~') {    /* Has a version number */
  1708.         t = atoi(xp+2);                /* Get it */
  1709.         if (t > d) d = t;    /* Save d = highest version number */
  1710.         }
  1711.     }
  1712.     if (d < power-1) {        /* Less than maximum possible? */
  1713.         sprintf(bp,".~%d~",d+1);    /* Yes, make "name.~<d+1>~" */
  1714.         *s = buf;            /* Point to new name */
  1715.         break;            /* Done, return it */
  1716.     }
  1717.     }
  1718.     if (*s == NULL) {
  1719.     sprintf(bp,".~xxxx~");        /* Too many, use xxxx. */
  1720.     *s = buf;
  1721.     }
  1722. #ifdef OS2
  1723.     if (IsFileNameValid(buf))
  1724.         return; /* HPFS */
  1725.     /* otherwise make FAT 8.3 name */
  1726.     xp = bp = buf;
  1727.     yp = fn;
  1728.     while (*yp) {            /* Copy name into buf */
  1729.     ch = *bp++ = *yp++;
  1730.     if (ISDIRSEP(ch) || (ch == ':')) xp=bp;
  1731.     }
  1732.     *bp = '\0';
  1733.     yp = xp;
  1734.     i = 1;
  1735.     while (*yp && (*yp != '.')) {
  1736.     yp++;
  1737.     if (++i<=6) zp=yp;
  1738.     }
  1739.     /* zp points to 6th character in name, or yp, whichever occurs first. */
  1740.     strcpy(temp,yp);            /* Copy extension, if any */
  1741.     while (zp != xp+8) {
  1742.         if ( zp < xp+5 ) *zp++='0';
  1743.         else *zp++='?';            /* Pad out with wild cards */
  1744.     }
  1745.     strcpy(zp,temp);            /* Get the extension back */
  1746.     n = zxpand(buf);            /* Expand the resulting wild name */
  1747.     d = 0;                /* Index number */
  1748.     while (znext(temp)) {
  1749.         i = atoi(temp+5);
  1750.         if (i > d) d = i;
  1751.     }
  1752.     sprintf(temp,"%03d",d+1);        /* get the number into a string */
  1753.     memcpy(xp+5, temp, 3);
  1754. #endif /* OS2 */
  1755.     return;
  1756. }
  1757.  
  1758.  
  1759. /*  Z R E N A M E  --  Rename a file  */
  1760.  
  1761. /*  Note, link() and unlink() are used because rename() is not available  */
  1762. /*  in some versions of UNIX.   */
  1763. /*  Call with old and new names */
  1764. /*  Returns 0 on success, -1 on failure. */
  1765.  
  1766. int
  1767. zrename(old,new) char *old, *new; {
  1768. #ifdef RENAME
  1769. /*
  1770.   Atomic, preferred.
  1771. */
  1772.    return(rename(old, new));
  1773. #else /* !RENAME */
  1774. /*
  1775.   This way has a window of vulnerability.
  1776. */
  1777.    if (link(old,new) < 0) {        /* Make a link with the new name. */
  1778.     debug(F111,"zrename link fails, errno",old,errno);
  1779.     return(-1);
  1780.     }
  1781.     if (unlink(old) < 0) {        /* Unlink the old name. */
  1782.     debug(F111,"zrename unlink fails, errno",old,errno);
  1783.     return(-1);
  1784.     }
  1785.     return(0);
  1786. #endif /* RENAME */
  1787. }
  1788.  
  1789. /*  Z S A T T R */
  1790. /*
  1791.  Fills in a Kermit file attribute structure for the file which is to be sent.
  1792.  Returns 0 on success with the structure filled in, or -1 on failure.
  1793.  If any string member is null, then it should be ignored.
  1794.  If any numeric member is -1, then it should be ignored.
  1795. */
  1796. int
  1797. zsattr(xx) struct zattr *xx; {
  1798.     long k;
  1799.  
  1800.     k = iflen % 1024L;            /* File length in K */
  1801.     if (k != 0L) k = 1L;
  1802.     xx->lengthk = (iflen / 1024L) + k;
  1803.     xx->type.len = 0;            /* File type can't be filled in here */
  1804.     xx->type.val = "";
  1805.     if (*nambuf) {
  1806.     xx->date.val = zfcdat(nambuf);    /* File creation date */
  1807.     xx->date.len = (int)strlen(xx->date.val);
  1808.     } else {
  1809.     xx->date.len = 0;
  1810.     xx->date.val = "";
  1811.     }
  1812.     xx->creator.len = 0;        /* File creator */
  1813.     xx->creator.val = "";
  1814.     xx->account.len = 0;        /* File account */
  1815.     xx->account.val = "";
  1816.     xx->area.len = 0;            /* File area */
  1817.     xx->area.val = "";
  1818.     xx->passwd.len = 0;            /* Area password */
  1819.     xx->passwd.val = "";
  1820.     xx->blksize = -1L;            /* File blocksize */
  1821.     xx->access.len = 0;            /* File access */
  1822.     xx->access.val = "";
  1823.     xx->encoding.len = 0;        /* Transfer syntax */
  1824.     xx->encoding.val = 0;
  1825.     xx->disp.len = 0;            /* Disposition upon arrival */
  1826.     xx->disp.val = "";
  1827.     xx->lprotect.len = 0;        /* Local protection */
  1828.     xx->lprotect.val = "";
  1829.     xx->gprotect.len = 0;        /* Generic protection */
  1830.     xx->gprotect.val = "";
  1831.     xx->systemid.len = 2;        /* System ID */
  1832.     xx->systemid.val = "U1";
  1833.     xx->recfm.len = 0;            /* Record format */
  1834.     xx->recfm.val = "";
  1835.     xx->sysparam.len = 0;        /* System-dependent parameters */
  1836.     xx->sysparam.val = "";
  1837.     xx->length = iflen;            /* Length */
  1838.     return(0);
  1839. }
  1840.  
  1841. /* Z F C D A T  --  Get file creation date */
  1842. /*
  1843.   Call with pointer to filename.
  1844.   On success, returns pointer to modification date in yyyymmdd hh:mm:ss format.
  1845.   On failure, returns pointer to null string.
  1846. */
  1847. static char datbuf[40];
  1848.  
  1849. /* static */                /* (===OS2 change===) */
  1850. char *
  1851. zfcdat(name) char *name; {
  1852.  
  1853. #ifdef TIMESTAMP
  1854.     struct stat buffer;
  1855.     struct tm *time_stamp, *localtime();
  1856.     int yy, ss;
  1857.  
  1858.     datbuf[0] = '\0';
  1859.     if(stat(name,&buffer) != 0) {
  1860.     debug(F110,"zfcdat stat failed",name,0);
  1861.     return("");
  1862.     }
  1863.     time_stamp = localtime(&(buffer.st_mtime));
  1864.     yy = time_stamp->tm_year;
  1865.     if (yy < 100)            /* In case it returns 2-digit year? */
  1866.       yy += 1900;
  1867.     if (yy < 0 || yy > 9999) {        /* Make sure year is ok */
  1868.     debug(F110,"zfcdat date failed",name,0);
  1869.     return("");
  1870.     }
  1871.     if (time_stamp->tm_mon  < 0 || time_stamp->tm_mon  > 11)
  1872.       return("");
  1873.     if (time_stamp->tm_mday < 0 || time_stamp->tm_mday > 31)
  1874.       return("");
  1875.     if (time_stamp->tm_hour < 0 || time_stamp->tm_hour > 23)
  1876.       return("");
  1877.     if (time_stamp->tm_min  < 0 || time_stamp->tm_min  > 59)
  1878.       return("");
  1879.     ss = time_stamp->tm_sec;        /* Seconds */
  1880.     if (ss < 0 || ss  > 59)        /* Some systems give a BIG number */
  1881.       ss = 0;
  1882.     sprintf(datbuf,
  1883. #ifdef pdp11
  1884. /* For some reason, 2.1x BSD sprintf gets the last field wrong. */
  1885.         "%04d%02d%02d %02d:%02d:00",
  1886. #else
  1887.         "%04d%02d%02d %02d:%02d:%02d",
  1888. #endif /* pdp11 */
  1889.         yy,
  1890.         time_stamp->tm_mon + 1,
  1891.         time_stamp->tm_mday,
  1892.         time_stamp->tm_hour,
  1893.         time_stamp->tm_min
  1894. #ifndef pdp11
  1895.         , ss
  1896. #endif /* pdp11 */
  1897.         );
  1898.     yy = (int)strlen(datbuf);
  1899.     debug(F111,"zfcdat",datbuf,yy);
  1900.     if (yy > 17) datbuf[17] = '\0';
  1901.     return(datbuf);
  1902. #else
  1903.     return("");
  1904. #endif /* TIMESTAMP */
  1905. }
  1906.  
  1907. /* Z S T I M E  --  Set creation date for incoming file */
  1908. /*
  1909.  Call with:
  1910.  f  = pointer to name of existing file.
  1911.  yy = pointer to a Kermit file attribute structure in which yy->date.val
  1912.       is a date of the form yyyymmdd hh:mm:ss, e.g. 19900208 13:00:00.
  1913.  x  = is a function code: 0 means to set the file's creation date as given.
  1914.       1 means compare the given date with the file creation date.
  1915.  Returns:
  1916.  -1 on any kind of error.
  1917.   0 if x is 0 and the file date was set successfully.
  1918.   0 if x is 1 and date from attribute structure <= file creation date.
  1919.   1 if x is 1 and date from attribute structure > file creation date.
  1920. */
  1921. int
  1922. zstime(f,yy,x) char *f; struct zattr *yy; int x; {
  1923.     int r = -1;                /* return code */
  1924. /*
  1925.   It is ifdef'd TIMESTAMP because it might not work on V7. bk@kullmar.se.
  1926. */
  1927. #ifdef TIMESTAMP
  1928. /*
  1929.   To do: adapt code from OS-9 Kermit's ck9fio.c zstime function, which
  1930.   is more flexible, allowing [yy]yymmdd[ hh:mm[:ss]].
  1931. */
  1932. #ifndef OS2
  1933. #ifndef ODT30
  1934.     extern int ftime();
  1935.     extern int stat();
  1936. #endif /* ODT30 */
  1937. #ifdef BSD44
  1938.     extern int utimes();
  1939. #else
  1940.     extern int utime();
  1941. #endif /* BSD44 */
  1942.     /* at least, the declarations for int functions are not needed anyway */
  1943.     extern struct tm *localtime();
  1944.     /* and this should have been declared always through a header file */
  1945. #endif /* OS2 */
  1946.     long tm, days;
  1947.     int i, n, isleapyear;
  1948.                    /*       J  F  M  A   M   J   J   A   S   O   N   D   */
  1949.                    /*      31 28 31 30  31  30  31  31  30  31  30  31   */
  1950.     static
  1951.     int monthdays [13] = {  0,0,31,59,90,120,151,181,212,243,273,304,334 };
  1952.     char s[5];
  1953.     struct stat sb;
  1954. #ifdef BSD44
  1955.     struct timeval tp[2];
  1956. #else
  1957. #ifdef OS2
  1958.     struct utimbuf tp;
  1959. #ifdef __EMX__
  1960.     long timezone;
  1961.     struct timeb tbp;
  1962. #endif /* __EMX__ */
  1963. #else
  1964. #ifdef V7
  1965.     struct utimbuf {
  1966.       time_t timep[2];        /* New access and modificaton time */
  1967.     } tp;
  1968.     char *tz;
  1969.     long timezone;        /* In case timezone not defined in .h file */
  1970. #else
  1971. #ifdef SYSUTIMEH
  1972.     struct utimbuf tp;
  1973. #else
  1974.     struct utimbuf {
  1975.       time_t atime;        /* New access time */
  1976.       time_t mtime;        /* New modification time */
  1977.     } tp;
  1978. #endif /* SYSUTIMEH */
  1979. #endif /* V7 */
  1980. #endif /* OS2 */
  1981. #endif /* BSD44 */
  1982.  
  1983. #ifdef ANYBSD
  1984.     long timezone;
  1985.     static struct timeb tbp;
  1986. #endif /* ANYBSD */
  1987.  
  1988.     debug(F110,"zstime",f,0);
  1989.  
  1990.     if ((yy->date.len == 0)
  1991.         || (yy->date.len != 17)
  1992.         || (yy->date.val[8] != ' ')
  1993.         || (yy->date.val[11] != ':')
  1994.         || (yy->date.val[14] != ':') ) {
  1995.         debug(F111,"Bad creation date ",yy->date.val,yy->date.len);
  1996.         return(-1);
  1997.     }
  1998.     debug(F111,"zstime date check 1",yy->date.val,yy->date.len);
  1999.     for(i = 0; i < 8; i++) {
  2000.     if (!isdigit(yy->date.val[i])) {
  2001.         debug(F111,"Bad creation date ",yy->date.val,yy->date.len);
  2002.         return(-1);
  2003.     }
  2004.     }
  2005.     debug(F111,"zstime date check 2",yy->date.val,yy->date.len);
  2006.     i++;
  2007.  
  2008.     for (; i < 16; i += 3) {
  2009.     if ((!isdigit(yy->date.val[i])) || (!isdigit(yy->date.val[i + 1]))) {
  2010.         debug(F111,"Bad creation date ",yy->date.val,yy->date.len);
  2011.         return(-1);
  2012.     }
  2013.     }
  2014.     debug(F111,"zstime date check 3",yy->date.val,yy->date.len);
  2015.  
  2016. #ifdef ANYBSD
  2017.     debug(F100,"ztime BSD calling ftime","",0);
  2018.     ftime(&tbp);
  2019.     debug(F100,"ztime BSD back from ftime","",0);
  2020.     timezone = tbp.timezone * 60L;
  2021.     debug(F101,"ztime BSD timezone","",timezone);
  2022. #endif /* ANYBSD */
  2023.  
  2024. #ifdef OS2
  2025. #ifdef __EMX__
  2026.     ftime(&tbp);
  2027.     timezone = tbp.timezone * 60L;
  2028. #endif /* __EMX__ */
  2029. #endif /* OS2 */
  2030.  
  2031. #ifdef SVORPOSIX
  2032.     tzset();                /* Set timezone */
  2033. #endif /* SVORPOSIX */
  2034.  
  2035. #ifdef V7
  2036.     if ((tz = getenv("TZ")) == NULL)
  2037.       timezone = 0;            /* UTC/GMT */
  2038.     else
  2039.       timezone = atoi(&tz[3]);        /* Set 'timezone'. */
  2040.     timezone *= 60L;
  2041. #endif /* V7 */
  2042.  
  2043.     debug(F100,"zstime so far so good","",0);
  2044.  
  2045.     s[4] = '\0';
  2046.     for (i = 0; i < 4; i++)        /* Fix the year */
  2047.       s[i] = yy->date.val[i];
  2048.  
  2049.     n = atoi(s);
  2050.  
  2051.     debug(F111,"zstime year",s,n);
  2052.  
  2053. /*  Previous year's leap days.  This won't work after year 2100. */
  2054.  
  2055.     isleapyear = (( n % 4 == 0 && n % 100 !=0) || n % 400 == 0);
  2056.     days = (long) (n - 1970) * 365;
  2057.     days += (n - 1968 - 1) / 4 - (n - 1900 - 1) / 100 + (n - 1600 - 1) / 400;
  2058.  
  2059.     s[2] = '\0';
  2060.  
  2061.     for (i = 4 ; i < 16; i += 2) {
  2062.     s[0] = yy->date.val[i];
  2063.     s[1] = yy->date.val[i + 1];
  2064.     n = atoi(s);
  2065.     switch (i) {
  2066.       case 4:            /* MM: month */
  2067.         if ((n < 1 ) || ( n > 12)) {
  2068.         debug(F111,"zstime 4 bad date ",yy->date.val,yy->date.len);
  2069.         return(-1);
  2070.         }
  2071.         days += monthdays [n];
  2072.         if (isleapyear && n > 2)
  2073.           ++days;
  2074.         continue;
  2075.  
  2076.       case 6:            /* DD: day */
  2077.         if ((n < 1 ) || ( n > 31)) {
  2078.         debug(F111,"zstime 6 bad date ",yy->date.val,yy->date.len);
  2079.         return(-1);
  2080.         }
  2081.         tm = (days + n - 1) * 24L * 60L * 60L;
  2082.         i++;            /* Skip the space */
  2083.         continue;
  2084.  
  2085.       case 9:            /* hh: hour */
  2086.         if ((n < 0 ) || ( n > 23)) {
  2087.         debug(F111,"zstime 9 bad date ",yy->date.val,yy->date.len);
  2088.         return(-1);
  2089.         }
  2090.         tm += n * 60L * 60L;
  2091.         i++;            /* Skip the colon */
  2092.         continue;
  2093.  
  2094.       case 12:            /* mm: minute */
  2095.         if ((n < 0 ) || ( n > 59)) {
  2096.         debug(F111,"zstime 12 bad date ",yy->date.val,yy->date.len);
  2097.         return(-1);
  2098.         }
  2099. #ifdef ANYBSD                /* Correct for time zone */
  2100.         tm += timezone;
  2101. #else
  2102. #ifndef BSD44                /* For now... */
  2103. #ifndef CONVEX9
  2104. /*
  2105.   How to accomplish this for these systems is still a mystery.
  2106. */
  2107. #ifdef ultrix
  2108.         tm += (long) timezone;
  2109. #else
  2110.         tm += timezone;
  2111. #endif /* ultrix */
  2112. #endif /* CONVEX9 */
  2113. #endif /* BSD44 */
  2114. #endif /* ANYBSD */
  2115.         tm += n * 60L;
  2116.         i++;            /* Skip the colon */
  2117.         continue;
  2118.  
  2119.       case 15:            /* ss: second */
  2120.         if ((n < 0 ) || ( n > 59)) {
  2121.         debug(F111,"zstime 15 bad date ",yy->date.val,yy->date.len);
  2122.         return(-1);
  2123.         }
  2124.         tm += n;
  2125.     }
  2126.     if (localtime(&tm)->tm_isdst)
  2127.       tm -= 60L * 60L;        /* Adjust for daylight savings time */
  2128.     }
  2129.     debug(F101,"tm","",tm);
  2130.     debug(F111,"A-pkt date ok ",yy->date.val,yy->date.len);
  2131.  
  2132.     if (stat(f,&sb)) {            /* Get the time for the file */
  2133.     debug(F110,"Can't stat file:",f,0);
  2134.     return(-1);
  2135.     }
  2136.     debug(F101,"sb.st_atime","",sb.st_atime);
  2137.  
  2138. #ifdef OS2
  2139.     tp.modtime = tm;            /* Set modif. time to creation date */
  2140.     tp.actime = sb.st_atime;        /* Don't change the access time */
  2141. #else
  2142. #ifdef SYSUTIMEH
  2143.     tp.modtime = tm;            /* Set modif. time to creation date */
  2144.     tp.actime = sb.st_atime;        /* Don't change the access time */
  2145. #else
  2146. #ifdef V7
  2147.     tp.timep[0] = tm;            /* Set modif. time to creation date */
  2148.     tp.timep[1] = sb.st_atime;        /* Don't change the access time */
  2149. #else
  2150. #ifdef BSD44
  2151.     tp[0].tv_sec = sb.st_atime;        /* Access time first */
  2152.     tp[1].tv_sec = tm;            /* Update time second */
  2153. #else
  2154.     tp.mtime = tm;            /* Set modif. time to creation date */
  2155.     tp.atime = sb.st_atime;        /* Don't change the access time */
  2156. #endif /* BSD44 */
  2157. #endif /* V7 */
  2158. #endif /* SYSUTIMEH */
  2159. #endif /* OS2 */
  2160.  
  2161.     switch (x) {            /* Execute desired function */
  2162.       case 0:                /* Set the creation date of the file */
  2163.     if (
  2164. #ifdef BSD44
  2165.         utimes(f,tp)
  2166. #else
  2167.         utime(f,&tp)
  2168. #endif /* BSD44 */
  2169.         ) {        /* Fix modification time */
  2170.         debug(F110,"Can't set modification time for file: ",f,0);
  2171.         r = -1;
  2172.     } else  {
  2173.         debug(F110,"Modification time is set for file: ",f,0);
  2174.         r = 0;
  2175.     }
  2176.     break;
  2177.       case 1:                /* Compare the dates */
  2178. /*
  2179.   This was st_atime, which was wrong.  We want the file-data modification
  2180.   time, st_mtime.
  2181. */
  2182.     debug(F111,"zstime compare",f,sb.st_mtime);
  2183.     debug(F111,"zstime compare","packet",tm);
  2184.     r = (sb.st_mtime < tm) ? 0 : 1;
  2185.     break;
  2186.       default:                /* Error */
  2187.     r = -1;
  2188.     }
  2189. #endif /* TIMESTAMP */
  2190.     return(r);
  2191. }
  2192.  
  2193. /* Find initialization file. */
  2194.  
  2195. #ifdef NOTUSED
  2196. int
  2197. zkermini() {
  2198. /*  nothing here for Unix.  This function added for benefit of VMS Kermit.  */
  2199.     return(0);
  2200. }
  2201. #endif /* NOTUSED */
  2202.  
  2203. #ifndef NOFRILLS
  2204. int
  2205. zmail(p,f) char *p; char *f; {        /* Send file f as mail to address p */
  2206. /*
  2207.   Returns 0 on success
  2208.    2 if mail delivered but temp file can't be deleted
  2209.   -2 if mail can't be delivered
  2210.   The UNIX version always returns 0 because it can't get a good return
  2211.   code from zsyscmd.
  2212. */
  2213. #ifdef BSD4
  2214. /* The idea is to use /usr/ucb/mail, rather than regular mail, so that   */
  2215. /* a subject line can be included with -s.  Since we can't depend on the */
  2216. /* user's path, we use the convention that /usr/ucb/Mail = /usr/ucb/mail */
  2217. /* and even if Mail has been moved to somewhere else, this should still  */
  2218. /* find it...  The search could be made more reliable by actually using  */
  2219. /* access() to see if /usr/ucb/Mail exists. */
  2220.  
  2221. /* Should also make some check on zmbuf overflow... */
  2222.  
  2223. #ifdef DGUX540
  2224.     sprintf(zmbuf,"mailx -s %c%s%c %s < %s", '"', f, '"', p, f);
  2225. #else
  2226.     sprintf(zmbuf,"Mail -s %c%s%c %s < %s", '"', f, '"', p, f);
  2227. #endif /* DGUX540 */
  2228.     zsyscmd(zmbuf);
  2229. #else
  2230. #ifdef SVORPOSIX
  2231. #ifndef OXOS
  2232.     sprintf(zmbuf,"mail %s < %s", p, f);
  2233. #else /* OXOS */
  2234.     sprintf(zmbuf,"mailx -s %c%s%c %s < %s", '"', f, '"', p, f);
  2235. #endif /* OXOS */
  2236.     zsyscmd(zmbuf);
  2237. #else
  2238.     *zmbuf = '\0';
  2239. #endif
  2240. #endif
  2241.     return(0);
  2242. }
  2243. #endif /* NOFRILLS */
  2244.  
  2245. #ifndef NOFRILLS
  2246. int
  2247. zprint(p,f) char *p; char *f; {        /* Print file f with options p */
  2248.  
  2249. #ifdef OS2
  2250.     sprintf(zmbuf,"print %s %s", p, f); /* Construct print command */
  2251.     zsyscmd(zmbuf);
  2252. #else
  2253. #ifdef UNIX
  2254. #ifdef ANYBSD                /* BSD uses lpr to spool */
  2255. #ifdef DGUX540                /* And DG/UX */
  2256. #define SPOOLER "lp"
  2257. #else
  2258. #define SPOOLER "lpr"
  2259. #endif /* DGUX540 */
  2260. #else                    /* Sys V uses lp */
  2261. #ifdef TRS16                /* except for Tandy-16/6000... */
  2262. #define SPOOLER "lpr"
  2263. #else
  2264. #define SPOOLER "lp"
  2265. #endif
  2266. #endif
  2267. /*
  2268.   Note use of standard input redirection.  In some systems, lp[r] runs
  2269.   setuid to lp (or ...?), so if user has sent a file into a directory
  2270.   that lp does not have read access to, it can't be printed unless it is
  2271.   feed to lp[r] as standard input.
  2272. */
  2273.     sprintf(zmbuf,"%s %s < %s", SPOOLER, p, f); /* Construct print command */
  2274.     zsyscmd(zmbuf);
  2275. #else /* Not UNIX */
  2276.     *zmbuf = '\0';
  2277. #endif /* UNIX */
  2278. #endif /* OS2 */
  2279.     return(0);
  2280. }
  2281. #endif /* NOFRILLS */
  2282.  
  2283. /*
  2284.   Wildcard expansion functions.  C-Kermit used to insist on doing this itself
  2285.   New code (version 5A, 1990-91) gives user option to ask UNIX to do it.
  2286.   This lets users use the wildcard expansion features of their favorite shell.
  2287.   Operation is slower because of the forking & piping, but flexibility is
  2288.   greater and program is smaller.  For OS/2, C-Kermit still does this itself.
  2289. */
  2290. static char scratch[MAXPATH+4];        /* Used by both methods */
  2291.  
  2292. #ifndef OS2
  2293. static int oldmtchs = 0;        /* Let shell (ls) expand them. */
  2294. #ifdef COMMENT
  2295. static char *lscmd = "/bin/ls -d";     /* Command to use. */
  2296. #else
  2297. static char *lscmd = "echo";        /* Command to use. */
  2298. #endif /* COMMENT */
  2299.  
  2300. int
  2301. shxpand(pat,namlst,len) char *pat, *namlst[]; int len; {
  2302.     char *fgbuf = NULL;            /* Buffer for forming ls command */
  2303.     char *p, *q;            /* Workers */
  2304.     int i, x, retcode; char c;        /* ... */
  2305.  
  2306.     x = (int)strlen(pat) + (int)strlen(lscmd) + 3; /* Length of ls command */
  2307.     for (i = 0; i < oldmtchs; i++)    /* Free previous file list */
  2308.       free(namlst[i]);
  2309.     fgbuf = malloc(x);            /* Get buffer for command */
  2310.     if (!fgbuf) return(-1);        /* Fail if cannot */
  2311.     sprintf(fgbuf,"%s %s",lscmd,pat);    /* Form the command */
  2312.     zxcmd(ZIFILE,fgbuf);        /* Start the command */
  2313.     i = 0;                /* File counter */
  2314.     p = scratch;            /* Point to scratch area */
  2315.     retcode = -1;            /* Assume failure */
  2316.     while ((x = zminchar()) != -1) {    /* Read characters from command */
  2317.     c = (char) x;
  2318.     if (c == ' ' || c == '\n') {    /* Got newline or space? */
  2319.         *p = '\0';            /* Yes, terminate string */
  2320.         p = scratch;        /* Point back to beginning */
  2321.         if (zchki(p) == -1)        /* Does file exist? */
  2322.           continue;            /* No, continue */
  2323.         x = (int)strlen(p);        /* Yes, get length of name */
  2324.         q = malloc(x+1);        /* Allocate space for it */
  2325.         if (!q) goto shxfin;    /* Fail if space can't be obtained */
  2326.         strcpy(q,scratch);        /* Copy name to space */
  2327.         namlst[i++] = q;        /* Copy pointer to name into array */
  2328.         if (i > len) goto shxfin;    /* Fail if too many */
  2329.     } else {            /* Regular character */
  2330.         *p++ = c;            /* Copy it into scratch area */
  2331.     }
  2332.     }
  2333.     retcode = i;            /* Return number of matching files */
  2334. shxfin:                    /* Common exit point */
  2335.     free(fgbuf);            /* Free command buffer */
  2336.     zclosf(ZIFILE);            /* Delete the command fork. */
  2337.     oldmtchs = i;            /* Remember how many files */
  2338.     return(retcode);
  2339. }
  2340. #endif /* OS2 */
  2341.  
  2342. /* Directory Functions for Unix, written by Jeff Damens, CUCCA, 1984. */
  2343.  
  2344. /* Define the size of the string space for filename expansion. */
  2345.  
  2346. #ifndef DYNAMIC
  2347. #ifdef PROVX1
  2348. #define SSPACE 500
  2349. #else
  2350. #ifdef BSD29
  2351. #define SSPACE 500
  2352. #else
  2353. #ifdef pdp11
  2354. #define SSPACE 500
  2355. #else
  2356. #ifdef aegis
  2357. #define SSPACE 10000            /* size of string-generating buffer */
  2358. #else                    /* Default static buffer size */
  2359. #define SSPACE 2000            /* size of string-generating buffer */
  2360. #endif /* aegis */
  2361. #endif /* pdp11 */
  2362. #endif /* BSD29 */
  2363. #endif /* PROVX1 */
  2364. static char sspace[SSPACE];             /* buffer for generating filenames */
  2365. #else /* DYNAMIC */
  2366. #define SSPACE 10000
  2367. static char *sspace = (char *)0;
  2368. #endif /* DYNAMIC */
  2369. #ifdef aegis
  2370. static char bslash;
  2371. #endif /* aegis */
  2372. static int ssplen = SSPACE;        /* length of string space buffer */
  2373.  
  2374. static char *freeptr,**resptr;             /* copies of caller's arguments */
  2375. static int remlen;                      /* remaining length in caller's array*/
  2376. static int numfnd;                      /* number of matches found */
  2377.  
  2378. /*
  2379.  * splitpath:
  2380.  *  takes a string and splits the slash-separated portions into
  2381.  *  a list of path structures.  Returns the head of the list.  The
  2382.  *  structures are allocated by malloc, so they must be freed.
  2383.  *  Splitpath is used internally by the filename generator.
  2384.  *
  2385.  * Input: A string.
  2386.  * Returns: A linked list of the slash-separated segments of the input.
  2387.  */
  2388.  
  2389. struct path *
  2390. splitpath(p) char *p; {
  2391.     struct path *head,*cur,*prv;
  2392.     int i;
  2393.  
  2394.     debug(F110,"splitpath",p,0);
  2395.  
  2396.     head = prv = NULL;
  2397.     if (ISDIRSEP(*p)) p++;            /* skip leading slash */
  2398.     while (*p != '\0') {
  2399.     cur = (struct path *) malloc(sizeof (struct path));
  2400.     debug(F101,"splitpath malloc","",cur);
  2401.     if (cur == NULL) {
  2402.         debug(F100,"splitpath malloc failure","",0);
  2403.         return((struct path *)NULL);
  2404.     }
  2405.     cur -> fwd = NULL;
  2406.     if (head == NULL)
  2407.       head = cur;
  2408.     else
  2409.       prv -> fwd = cur;        /* link into chain */
  2410.     prv = cur;
  2411. #ifdef aegis
  2412.     /* treat backslash as "../" */
  2413.     if (bslash && *p == bslash) {
  2414.         strcpy(cur->npart, "..");
  2415.         ++p;
  2416.     } else {
  2417.         for (i=0; i < MAXNAMLEN && *p && *p != '/' && *p != bslash; i++)
  2418.           cur -> npart[i] = *p++;
  2419.         cur -> npart[i] = '\0';    /* end this segment */
  2420.         if (i >= MAXNAMLEN)
  2421.           while (*p && *p != '/' && *p != bslash)
  2422.         p++;
  2423.     }
  2424.     if (*p == '/') p++;
  2425. #else
  2426. #ifdef OS2
  2427.     for (i = 0;
  2428.          i < MAXNAMLEN && !ISDIRSEP(*p) && *p != ':' && *p != '\0';
  2429.          i++ )
  2430.         cur -> npart[i] = *p++;
  2431.         if ( *p == ':' ) {
  2432.             cur -> npart[i++] = *p++;
  2433.             if ( !ISDIRSEP(*p) )
  2434.                 cur -> npart[i++] = '.';
  2435.         }
  2436. #else
  2437.     for (i=0; i < MAXNAMLEN && !ISDIRSEP(*p) && *p != '\0'; i++) {
  2438.         cur -> npart[i] = *p++;
  2439.     }
  2440. #endif /* OS2 */
  2441.     cur -> npart[i] = '\0';        /* end this segment */
  2442.     if (i >= MAXNAMLEN)
  2443.       while (!ISDIRSEP(*p) && *p != '\0') p++;
  2444.     if (ISDIRSEP(*p))
  2445.       p++;
  2446.  
  2447. #endif /* aegis */
  2448.     }
  2449.     return(head);
  2450. }
  2451.  
  2452. /*
  2453.  * fgen:
  2454.  *  This is the actual name generator.  It is passed a string,
  2455.  *  possibly containing wildcards, and an array of character pointers.
  2456.  *  It finds all the matching filenames and stores them into the array.
  2457.  *  The returned strings are allocated from a static buffer local to
  2458.  *  this module (so the caller doesn't have to worry about deallocating
  2459.  *  them); this means that successive calls to fgen will wipe out
  2460.  *  the results of previous calls.  This isn't a problem here
  2461.  *  because we process one wildcard string at a time.
  2462.  *
  2463.  * Input: a wildcard string, an array to write names to, the
  2464.  *        length of the array.
  2465.  * Returns: the number of matches.  The array is filled with filenames
  2466.  *          that matched the pattern.  If there wasn't enough room in the
  2467.  *        array, -1 is returned.
  2468.  * Originally by: Jeff Damens, CUCCA, 1984.  Many changes since then.
  2469.  */
  2470. static int
  2471. fgen(pat,resarry,len) char *pat,*resarry[]; int len; {
  2472.     struct path *head;
  2473.     char *sptr;
  2474. #ifdef aegis
  2475.     char *namechars;
  2476.     int tilde = 0, bquote = 0;
  2477.  
  2478.     if ((namechars = getenv("NAMECHARS")) != NULL) {
  2479.     if (xindex(namechars, '~' ) != NULL) tilde  = '~';
  2480.     if (xindex(namechars, '\\') != NULL) bslash = '\\';
  2481.     if (xindex(namechars, '`' ) != NULL) bquote = '`';
  2482.     } else {
  2483.     tilde = '~'; bslash = '\\'; bquote = '`';
  2484.     }
  2485.  
  2486.     sptr = scratch;
  2487.  
  2488.     /* copy "`node_data", etc. anchors */
  2489.     if (bquote && *pat == bquote)
  2490.       while (*pat && *pat != '/' && *pat != bslash)
  2491.     *sptr++ = *pat++;
  2492.     else if (tilde && *pat == tilde)
  2493.       *sptr++ = *pat++;
  2494.     while (*pat == '/')
  2495.       *sptr++ = *pat++;
  2496.     if (sptr == scratch) {
  2497.     strcpy(scratch,"./");
  2498.     sptr = scratch+2;
  2499.     }                    /* init buffer correctly */
  2500.     if (!(head = splitpath(pat))) return(-1);
  2501. #else /* not aegis */
  2502.     debug(F110,"fgen pat",pat,0);
  2503.     if (!(head = splitpath(pat))) return(-1);
  2504.     sptr = scratch;
  2505.     if (!ISDIRSEP(*pat))
  2506.     *sptr++ = '.';                  /* init buffer correctly */
  2507.     *sptr++ = DIRSEP;
  2508. #ifdef OS2
  2509.     if (isalpha(pat[0]) && pat[1] == ':')
  2510.         sptr = scratch;                 /* reset in case of leading drive: */
  2511. #endif /* OS2 */
  2512. #endif /* aegis */
  2513.     numfnd = 0;                /* none found yet */
  2514. #ifdef DYNAMIC
  2515.     if (!sspace) {            /* Need to allocate string space? */
  2516.     while (ssplen > 50) {
  2517.         if ((sspace = malloc(ssplen+2))) { /* Got it. */
  2518.         debug(F101,"fgen string space","",ssplen);
  2519.         break;
  2520.         }
  2521.         ssplen = (ssplen / 2) + (ssplen / 4); /* Didn't, reduce by 3/4 */
  2522.     }
  2523.     if (ssplen <= 50) {        /* Did we get it? */
  2524.         fprintf(stderr,"fgen can't malloc string space\n");
  2525.         return(-1);
  2526.     }
  2527.     }
  2528. #endif /* DYNAMIC */
  2529.     freeptr = sspace;            /* this is where matches are copied */
  2530.     resptr = resarry;            /* static copies of these so */
  2531.     remlen = len;            /* recursive calls can alter them */
  2532.     traverse(head,scratch,sptr);    /* go walk the directory tree */
  2533. #ifdef COMMENT
  2534. /*
  2535.   This code, circa 1984, has never worked right - it references the head
  2536.   pointer after it has already been freed.  Lord knows what might have been
  2537.   happening because of this.  Thanks to Steve Walton for finding & fixing
  2538.   this bug.
  2539. */
  2540.     for (; head != NULL; head = head -> fwd)
  2541.       free(head);            /* return the path segments */
  2542. #else
  2543.     while (head != NULL) {
  2544.     struct path *next = head -> fwd;
  2545.     free(head);
  2546.     head = next;
  2547.     }
  2548. #endif /* COMMENT */
  2549.     return(numfnd);            /* and return the number of matches */
  2550. }
  2551.  
  2552. /* traverse:
  2553.  *  Walks the directory tree looking for matches to its arguments.
  2554.  *  The algorithm is, briefly:
  2555.  *   If the current pattern segment contains no wildcards, that
  2556.  *   segment is added to what we already have.  If the name so far
  2557.  *   exists, we call ourselves recursively with the next segment
  2558.  *   in the pattern string; otherwise, we just return.
  2559.  *
  2560.  *   If the current pattern segment contains wildcards, we open the name
  2561.  *   we've accumulated so far (assuming it is really a directory), then read
  2562.  *   each filename in it, and, if it matches the wildcard pattern segment, add
  2563.  *   that filename to what we have so far and call ourselves recursively on the
  2564.  *   next segment.
  2565.  *
  2566.  *   Finally, when no more pattern segments remain, we add what's accumulated
  2567.  *   so far to the result array and increment the number of matches.
  2568.  *
  2569.  * Input: a pattern path list (as generated by splitpath), a string
  2570.  *      pointer that points to what we've traversed so far (this
  2571.  *      can be initialized to "/" to start the search at the root
  2572.  *      directory, or to "./" to start the search at the current
  2573.  *      directory), and a string pointer to the end of the string
  2574.  *      in the previous argument.
  2575.  * Returns: nothing.
  2576.  */
  2577. static VOID
  2578. traverse(pl,sofar,endcur) struct path *pl; char *sofar, *endcur; {
  2579.  
  2580. /* Define LONGFN (long file names) automatically for BSD 2.9 and 4.2 */
  2581. /* LONGFN can also be defined on the cc command line. */
  2582.  
  2583. #ifdef BSD29
  2584. #ifndef LONGFN
  2585. #define LONGFN
  2586. #endif
  2587. #endif
  2588.  
  2589. #ifdef BSD42
  2590. #ifndef LONGFN
  2591. #define LONGFN
  2592. #endif
  2593. #endif
  2594.  
  2595. /* Appropriate declarations for directory routines and structures */
  2596. /* #define OPENDIR means to use opendir(), readdir(), closedir()  */
  2597. /* If OPENDIR not defined, we use open(), read(), close() */
  2598.  
  2599. #ifdef DIRENT                /* New way, <dirent.h> */
  2600. #define OPENDIR
  2601.     DIR *fd, *opendir();
  2602.     struct dirent *dirbuf;
  2603.     struct dirent *readdir();
  2604. #else /* !DIRENT */
  2605. #ifdef LONGFN                /* Old way, <dir.h> with opendir() */
  2606. #define OPENDIR
  2607.     DIR *fd, *opendir();
  2608.     struct direct *dirbuf;
  2609. #else /* !LONGFN */
  2610.     int fd;                /* Old way, <dir.h> with open() */
  2611.     struct direct dir_entry;
  2612.     struct direct *dirbuf = &dir_entry;
  2613. #endif /* LONGFN */
  2614. #endif /* DIRENT */
  2615.  
  2616.     struct stat statbuf;        /* for file info */
  2617.  
  2618.     if (pl == NULL) {
  2619.     *--endcur = '\0';        /* end string, overwrite trailing / */
  2620.     addresult(sofar);
  2621.     return;
  2622.     }
  2623.     if (!iswild(pl -> npart)) {
  2624.     strcpy(endcur,pl -> npart);
  2625.     endcur += (int)strlen(pl -> npart);
  2626.     *endcur = '\0';            /* end current string */
  2627.     if (stat(sofar,&statbuf) == 0) { /* if current piece exists */
  2628. #ifdef OS2
  2629.         if (endcur - sofar == 3 && endcur[-1] == '.' && endcur[-2] == ':')
  2630.           endcur--;
  2631.         else
  2632. #endif /* OS2 */
  2633.           *endcur++ = DIRSEP;    /* add slash to end */
  2634.         *endcur = '\0';        /* and end the string */
  2635.         traverse(pl -> fwd,sofar,endcur);
  2636.     }
  2637.     return;
  2638.     }
  2639.  
  2640.     /* Segment contains wildcards, have to search directory */
  2641.  
  2642.     *endcur = '\0';                            /* end current string */
  2643.     if (stat(sofar,&statbuf) == -1) return;       /* doesn't exist, forget it */
  2644.     if (!S_ISDIR (statbuf.st_mode)) return;     /* not a directory, skip */
  2645.  
  2646. #ifdef OPENDIR
  2647.     if ((fd = opendir(sofar)) == NULL) return; /* Can't open, fail. */
  2648.     while (dirbuf = readdir(fd))
  2649. #else /* !OPENDIR */
  2650.     if ((fd = open(sofar,O_RDONLY)) < 0) return; /* Can't open, fail. */
  2651.     while (read(fd, (char *)dirbuf, sizeof dir_entry))
  2652. #endif /* OPENDIR */
  2653.       {
  2654.       /* Get null-terminated copy!!! */
  2655.       strncpy(nambuf,dirbuf->d_name,MAXNAMLEN);
  2656.       nambuf[MAXNAMLEN] = '\0';
  2657. #ifdef unos
  2658.       if (dirbuf->d_ino != -1 && match(pl -> npart,nambuf))
  2659. #else
  2660. /* #ifdef _POSIX_SOURCE */
  2661. /*
  2662.   Directory reading is not specified in POSIX.1.  POSIX.2 gives us glob() and
  2663.   fnmatch(), which are not yet supported by C-Kermit.  Meanwhile, maybe POSIX
  2664.   implementations should force "set wildcard shell" and remove all of this
  2665.   code.
  2666. */
  2667. #ifdef QNX
  2668.       if (dirbuf->d_stat.st_ino != 0 && match(pl -> npart,nambuf))
  2669. #else
  2670. #ifdef SOLARIS
  2671.       if (dirbuf->d_ino != 0 && match(pl -> npart,nambuf))
  2672. #else
  2673. #ifdef sun
  2674.       if (dirbuf->d_fileno != 0 && match(pl -> npart,nambuf))
  2675. #else
  2676. #ifdef bsdi
  2677.       if (dirbuf->d_fileno != 0 && match(pl -> npart,nambuf))
  2678. #else
  2679. #ifdef __386BSD__
  2680.       if (dirbuf->d_fileno != 0 && match(pl -> npart,nambuf))
  2681. #else
  2682. #ifdef ultrix
  2683.       if (dirbuf->gd_ino != 0 && match(pl -> npart,nambuf))
  2684. #else
  2685.       if (dirbuf->d_ino != 0 && match(pl -> npart,nambuf))
  2686. #endif /* ultrix */
  2687. #endif /* __386BSD__ */
  2688. #endif /* bsdi */
  2689. #endif /* sun */
  2690. #endif /* SOLARIS */
  2691. #endif /* QNX */
  2692.  
  2693. /* #else */ /* not _POSIX_SOURCE */
  2694. /*      if (dirbuf->d_ino != 0 && match(pl -> npart,nambuf)) */
  2695. /* #endif */ /* _POSIX_SOURCE */
  2696.  
  2697. #endif /* unos */
  2698.       {
  2699.           char *eos;
  2700.           strcpy(endcur,nambuf);
  2701.           eos = endcur + (int)strlen(nambuf);
  2702.           *eos++ = DIRSEP;        /* end this segment */
  2703.           traverse(pl -> fwd,sofar,eos);
  2704.       }
  2705.       }
  2706. #ifdef OPENDIR
  2707.     closedir(fd);
  2708. #else /* !OPENDIR */
  2709.     close(fd);
  2710. #endif /* OPENDIR */
  2711. }
  2712.  
  2713. /*
  2714.  * addresult:
  2715.  *  Adds a result string to the result array.  Increments the number
  2716.  *  of matches found, copies the found string into our string
  2717.  *  buffer, and puts a pointer to the buffer into the caller's result
  2718.  *  array.  Our free buffer pointer is updated.  If there is no
  2719.  *  more room in the caller's array, the number of matches is set to -1.
  2720.  * Input: a result string.
  2721.  * Returns: nothing.
  2722.  */
  2723. static VOID
  2724. addresult(str) char *str; {
  2725.     int l;
  2726.     debug(F111,"addresult",str,remlen);
  2727.     if (str[0] == '.' && ISDIRSEP(str[1])) str += 2; /* (===OS2 change===) */
  2728.     if (--remlen < 0) {
  2729.     numfnd = -1;
  2730.     return;
  2731.     }
  2732.     l = (int)strlen(str) + 1;        /* size this will take up */
  2733.     if ((freeptr + l) > (sspace + ssplen)) {
  2734.     numfnd = -1;            /* do not record if not enough space */
  2735.     return;
  2736.     }
  2737.     strcpy(freeptr,str);
  2738.     *resptr++ = freeptr;
  2739.     freeptr += l;
  2740.     numfnd++;
  2741. }
  2742.  
  2743. /*
  2744.  * match:
  2745.  *  pattern matcher.  Takes a string and a pattern possibly containing
  2746.  *  the wildcard characters '*' and '?'.  Returns true if the pattern
  2747.  *  matches the string, false otherwise.
  2748.  * by: Jeff Damens, CUCCA, 1984
  2749.  * skipping over dot files and backslash quoting added by fdc, 1990.
  2750.  *
  2751.  * Input: a string and a wildcard pattern.
  2752.  * Returns: 1 if match, 0 if no match.
  2753.  */
  2754. static int
  2755. match(pattern,string) char *pattern,*string; {
  2756.     char *psave,*ssave;            /* back up pointers for failure */
  2757.     int q = 0;                /* quote flag */
  2758.  
  2759.     debug(F110,"match str",string,0);
  2760.     psave = ssave = NULL;
  2761. #ifndef MATCHDOT
  2762.     if (*string == '.' && *pattern != '.') {
  2763.     debug(F110,"match skip",string,0);
  2764.     return(0);
  2765.     }
  2766. #endif
  2767.     while (1) {
  2768. #ifdef OS2
  2769.     for (; tolower(*pattern) == tolower(*string); pattern++,string++)
  2770. #else
  2771.     for (; *pattern == *string; pattern++,string++)  /* skip first */
  2772. #endif /* OS2 */
  2773.         if (*string == '\0') return(1);    /* end of strings, succeed */
  2774.  
  2775.     if (*pattern == '\\' && q == 0) { /* Watch out for quoted */
  2776.         q = 1;            /* metacharacters */
  2777.         pattern++;            /* advance past quote */
  2778.         if (*pattern != *string) return(0);
  2779.         continue;
  2780.     } else q = 0;
  2781.  
  2782.     if (q) {
  2783.         return(0);
  2784.     } else {
  2785.         if (*string != '\0' && *pattern == '?') {
  2786.         pattern++;        /* '?', let it match */
  2787.         string++;
  2788.         } else if (*pattern == '*') { /* '*' ... */
  2789.         psave = ++pattern;    /* remember where we saw it */
  2790.         ssave = string;        /* let it match 0 chars */
  2791.         } else if (ssave != NULL && *ssave != '\0') { /* if not at end  */
  2792.                     /* ...have seen a star */
  2793.         string = ++ssave;    /* skip 1 char from string */
  2794.         pattern = psave;    /* and back up pattern */
  2795.         } else return(0);        /* otherwise just fail */
  2796.     }
  2797.     }
  2798. }
  2799.  
  2800. /*
  2801.   The following two functions are for expanding tilde in filenames
  2802.   Contributed by Howie Kaye, CUCCA, developed for CCMD package.
  2803. */
  2804.  
  2805. /*  W H O A M I  --  Get user's username.  */
  2806.  
  2807. /*
  2808.   1) Get real uid
  2809.   2) See if the $USER environment variable is set ($LOGNAME on AT&T)
  2810.   3) If $USER's uid is the same as ruid, realname is $USER
  2811.   4) Otherwise get logged in user's name
  2812.   5) If that name has the same uid as the real uid realname is loginname
  2813.   6) Otherwise, get a name for ruid from /etc/passwd
  2814. */
  2815. static char *
  2816. whoami () {
  2817. #ifdef DTILDE
  2818. #ifdef pdp11
  2819. #define WHOLEN 100
  2820. #else
  2821. #define WHOLEN 257
  2822. #endif /* pdp11 */
  2823.     static char realname[256];        /* user's name */
  2824.     static int ruid = -1;        /* user's real uid */
  2825.     char loginname[256], envname[256];    /* temp storage */
  2826.     char *c;
  2827.     struct passwd *p;
  2828.     _PROTOTYP(extern char * getlogin, (void) );
  2829.  
  2830.     if (ruid != -1)
  2831.       return(realname);
  2832.  
  2833.     ruid = real_uid();            /* get our uid */
  2834.  
  2835.   /* how about $USER or $LOGNAME? */
  2836.     if ((c = getenv(NAMEENV)) != NULL) { /* check the env variable */
  2837.     strcpy (envname, c);
  2838.     if ((p = getpwnam(envname)) != NULL) {
  2839.         if (p->pw_uid == ruid) {    /* get passwd entry for envname */
  2840.         strcpy (realname, envname); /* if the uid's are the same */
  2841.         return(realname);
  2842.         }
  2843.     }
  2844.     }
  2845.  
  2846.   /* can we use loginname() ? */
  2847.  
  2848.     if ((c =  getlogin()) != NULL) {    /* name from utmp file */
  2849.     strcpy (loginname, c);
  2850.     if ((p = getpwnam(loginname)) != NULL) /* get passwd entry */
  2851.       if (p->pw_uid == ruid) {    /* for loginname */
  2852.           strcpy (realname, loginname); /* if the uid's are the same */
  2853.           return(realname);
  2854.       }
  2855.     }
  2856.  
  2857.   /* Use first name we get for ruid */
  2858.  
  2859.     if ((p = getpwuid(ruid)) == NULL) { /* name for uid */
  2860.     realname[0] = '\0';        /* no user name */
  2861.     ruid = -1;
  2862.     return(NULL);
  2863.     }
  2864.     strcpy (realname, p->pw_name);
  2865.     return(realname);
  2866. #else
  2867.     return(NULL);
  2868. #endif /* DTILDE */
  2869. }
  2870.  
  2871. /*  T I L D E _ E X P A N D  --  expand ~user to the user's home directory. */
  2872.  
  2873. char *
  2874. tilde_expand(dirname) char *dirname; {
  2875. #ifdef DTILDE
  2876. #ifdef pdp11
  2877. #define BUFLEN 100
  2878. #else
  2879. #define BUFLEN 257
  2880. #endif /* pdp11 */
  2881.     struct passwd *user;
  2882.     static char olddir[BUFLEN];
  2883.     static char oldrealdir[BUFLEN];
  2884.     static char temp[BUFLEN];
  2885.     int i, j;
  2886.  
  2887.     debug(F111,"tilde_expand",dirname,dirname[0]);
  2888.  
  2889.     if (dirname[0] != '~')        /* Not a tilde...return param */
  2890.       return(dirname);
  2891.     if (!strcmp(olddir,dirname)) {    /* Same as last time */
  2892.       return(oldrealdir);        /* so return old answer. */
  2893.     } else {
  2894.     j = (int)strlen(dirname);
  2895.     for (i = 0; i < j; i++)        /* find username part of string */
  2896.       if (!ISDIRSEP(dirname[i]))
  2897.         temp[i] = dirname[i];
  2898.       else break;
  2899.     temp[i] = '\0';            /* tie off with a NULL */
  2900.     if (i == 1) {            /* if just a "~" */
  2901.         user = getpwnam(whoami());    /*  get info on current user */
  2902.     } else {
  2903.         user = getpwnam(&temp[1]);    /* otherwise on the specified user */
  2904.     }
  2905.     }
  2906.     if (user != NULL) {            /* valid user? */
  2907.     strcpy(olddir, dirname);    /* remember the directory */
  2908.     strcpy(oldrealdir,user->pw_dir); /* and their home directory */
  2909.     strcat(oldrealdir,&dirname[i]);
  2910.     return(oldrealdir);
  2911.     } else {                /* invalid? */
  2912.     strcpy(olddir, dirname);    /* remember for next time */
  2913.     strcpy(oldrealdir, dirname);
  2914.     return(oldrealdir);
  2915.     }
  2916. #else
  2917.     return(NULL);
  2918. #endif /* DTILDE */
  2919. }
  2920.  
  2921. /*
  2922.   Functions for executing system commands.
  2923.   zsyscmd() executes the system command in the normal, default way for
  2924.   the system.  In UNIX, it does what system() does.  Thus, its results
  2925.   are always predictable.
  2926.   zshcmd() executes the command using the user's preferred shell.
  2927. */
  2928. int
  2929. zsyscmd(s) char *s; {
  2930. #ifdef aegis
  2931.     if (!priv_chk()) system(s);
  2932. #else
  2933. #ifdef OS2
  2934.     if (!priv_chk()) system(s);
  2935. #else
  2936.     PID_T shpid;
  2937. #ifdef COMMENT
  2938. /* This doesn't work... */
  2939.     WAIT_T status;
  2940. #else
  2941.     int status;
  2942. #endif /* COMMENT */
  2943.  
  2944.     if (shpid = fork()) {
  2945.     if (shpid < (PID_T)0) return(-1); /* Parent */
  2946.     while (shpid != (PID_T) wait(&status))
  2947.       ;
  2948.     return(status);
  2949.     }
  2950.     if (priv_can()) {            /* Child: cancel any priv's */
  2951.     printf("?Privilege cancellation failure\n");
  2952.     _exit(255);
  2953.     }
  2954.     execl("/bin/sh","sh","-c",s,NULL);
  2955.     perror("/bin/sh");
  2956.     _exit(255);
  2957.     return(0);                /* Shut up ANSI compilers. */
  2958. #endif /* OS2 */
  2959. #endif /* aegis */
  2960. }
  2961.  
  2962. /*
  2963.   UNIX code by H. Fischer; copyright rights assigned to Columbia Univ.
  2964.   Adapted to use getpwuid to find login shell because many systems do not
  2965.   have SHELL in environment, and to use direct calling of shell rather
  2966.   than intermediate system() call. -- H. Fischer
  2967.   Call with s pointing to command to execute.
  2968. */
  2969.  
  2970. int
  2971. zshcmd(s) char *s; {
  2972.     PID_T pid;
  2973.  
  2974. #ifdef OS2
  2975.     char *shell = getenv("COMSPEC");
  2976.     if (!priv_chk())
  2977.       if (*s == '\0')
  2978.         spawnl(P_WAIT, shell, shell, NULL);
  2979.       else
  2980.         system(s);
  2981. #else
  2982. #ifdef AMIGA
  2983.     if (!priv_chk()) system(s);
  2984. #else
  2985. #ifdef datageneral
  2986.     if (priv_chk) return(1);
  2987.     if (*s == '\0')            /* Interactive shell requested? */
  2988. #ifdef mvux
  2989.     system("/bin/sh ");
  2990. #else
  2991.         system("x :cli prefix Kermit_Baby:");
  2992. #endif /* mvux */
  2993.     else                /* Otherwise, */
  2994.         system(s);            /* Best for aos/vs?? */
  2995.  
  2996. #else
  2997. #ifdef aegis
  2998.     if ((pid = vfork()) == 0) {        /* Make child quickly */
  2999.     char *shpath, *shname, *shptr;    /* For finding desired shell */
  3000.  
  3001.     if (priv_can()) exit(1);    /* Turn off privs. */
  3002.         if ((shpath = getenv("SHELL")) == NULL) shpath = "/com/sh";
  3003.  
  3004. #else                    /* All Unix systems */
  3005.     if ((pid = fork()) == 0) {        /* Make child */
  3006.     char *shpath, *shname, *shptr;    /* For finding desired shell */
  3007.     struct passwd *p;
  3008.     char *defshell = "/bin/sh";    /* Default */
  3009.  
  3010.     if (priv_can()) exit(1);    /* Turn off privs. */
  3011. #ifdef COMMENT
  3012. /* Old way always used /etc/passwd shell */
  3013.     p = getpwuid(real_uid());    /* Get login data */
  3014.     if (p == (struct passwd *) NULL || !*(p->pw_shell))
  3015.       shpath = defshell;
  3016.     else
  3017.       shpath = p->pw_shell;
  3018. #else
  3019. /* New way lets user override with SHELL variable, but does not rely on it. */
  3020. /* This allows user to specify a different shell. */
  3021.     shpath = getenv("SHELL");    /* What shell? */
  3022.     if (shpath == NULL) {
  3023.         p = getpwuid( real_uid() );    /* Get login data */
  3024.         if (p == (struct passwd *)NULL || !*(p->pw_shell))
  3025.           shpath = defshell;
  3026.         else shpath = p->pw_shell;
  3027.         }
  3028. #endif /* COMMENT */
  3029. #endif /* aegis */
  3030.     shptr = shname = shpath;
  3031.     while (*shptr != '\0')
  3032.       if (*shptr++ == DIRSEP)
  3033.         shname = shptr;
  3034.     if (s == NULL || *s == '\0') {    /* Interactive shell requested? */
  3035.         execl(shpath,shname,"-i",NULL); /* Yes, do that */
  3036.     } else {            /* Otherwise, */
  3037.         execl(shpath,shname,"-c",s,NULL); /* exec the given command */
  3038.     }                /* If execl() failed, */
  3039.     exit(BAD_EXIT);            /* return bad return code. */
  3040.  
  3041.     } else {                /* Parent */
  3042.  
  3043.         int wstat;            /* ... must wait for child */
  3044.     SIGTYP (*istat)(), (*qstat)();
  3045.  
  3046.     if (pid == (PID_T) -1) return(0); /* fork() failed? */
  3047.  
  3048.     istat = signal(SIGINT,SIG_IGN);    /* Let the fork handle keyboard */
  3049.     qstat = signal(SIGQUIT,SIG_IGN); /* interrupts itself... */
  3050.  
  3051.         while (((wstat = wait((WAIT_T *)0)) != pid) && (wstat != -1))
  3052.       ;                /* Wait for fork */
  3053.     signal(SIGINT,istat);        /* Restore interrupts */
  3054.     signal(SIGQUIT,qstat);
  3055.     }
  3056. #endif
  3057. #endif
  3058. #endif
  3059.     return(1);
  3060. }
  3061.  
  3062. #ifdef aegis
  3063. /*
  3064.  Replacement for strchr() and index(), neither of which seem to be universal.
  3065. */
  3066.  
  3067. static char *
  3068. #ifdef CK_ANSIC
  3069. xindex(char * s, char c)
  3070. #else
  3071. xindex(s,c) char *s, c;
  3072. #endif /* CK_ANSIC */
  3073. /* xindex */ {
  3074.     while (*s != '\0' && *s != c) s++;
  3075.     if (*s == c) return(s); else return(NULL);
  3076. }
  3077. #endif /* aegis */
  3078.  
  3079. /*  I S W I L D  --  Check if filespec is "wild"  */
  3080.  
  3081. /*
  3082.   Returns 0 if it is a single file, 1 if it contains wildcard characters.
  3083.   Note: must match the algorithm used by match(), hence no [a-z], etc.
  3084. */
  3085. int
  3086. iswild(filespec) char *filespec; {
  3087.     char c; int x; char *p;
  3088.     if (wildxpand) {
  3089.     if ((x = zxpand(filespec)) > 1) return(1);
  3090.     if (x == 0) return(0);        /* File does not exist */
  3091.     p = malloc(MAXNAMLEN + 20);
  3092.     znext(p);
  3093. #ifdef OS2
  3094.     x = (stricmp(filespec,p) != 0);
  3095. #else
  3096.     x = (strcmp(filespec,p) != 0);
  3097. #endif
  3098.     free(p);
  3099.     return(x);
  3100.     } else {
  3101.     while ((c = *filespec++) != '\0')
  3102.       if (c == '*' || c == '?') return(1);
  3103.     return(0);
  3104.     }
  3105. }
  3106.  
  3107. #ifdef OS2
  3108.  
  3109. /*  Z C H D S K  --  Change currently selected disk device */
  3110.  
  3111. /* Returns -1 if error, otherwise 0 */
  3112.  
  3113. zchdsk(c) int c; {
  3114.     int i = toupper(c) - 64;
  3115.     return( _chdrive(i));
  3116. }
  3117.  
  3118. #undef stat
  3119. #ifdef __IBMC__STAT
  3120. #define stat(p, s) _stat(p, s)
  3121. #endif /* __IBMC__STAT */
  3122.  
  3123. os2stat(char *path, struct stat *st) {
  3124.     char local[MAXPATHLEN];
  3125.     int len;
  3126.  
  3127.     strcpy(local, path);
  3128.     len = strlen(local);
  3129.  
  3130.     if ( len == 2 && local[1] == ':' )
  3131.         local[2] = DIRSEP, local[3] = 0; /* if drive only, append / */
  3132.     else if ( len == 0 )
  3133.         local[0] = DIRSEP, local[1] = 0; /* if empty path, take / instead */
  3134.     else if ( len > 1 && ISDIRSEP(local[len - 1]) && local[len - 2] != ':' )
  3135.         local[len - 1] = 0; /* strip trailing / except after d: */
  3136.  
  3137.     return stat(local, st);
  3138. }
  3139.  
  3140. #endif /* OS2 */
  3141.